C ++为给定列表中的每种类型执行操作

时间:2017-02-15 16:55:24

标签: c++ c++11 templates refactoring variadic-templates

我被指控重构旧代码并且偶然发现了这个案例:

void myClass::doStuff()
{
    for( myIterator< Type1 > it( this->getDatabase() ); it; ++it )
    {
        do1( *it );
        do2( *it );
        do3( *it );
    }
    for( myIterator< Type2 > it( this->getDatabase() ); it; ++it )
    {
        do1( *it );
        do2( *it );
        do3( *it );
    }
    for( myIterator< Type3 > it( this->getDatabase() ); it; ++it )
    {
        do1( *it );
        do2( *it );
        do3( *it );
    }
}

它显然很糟糕,因为我基本上复制了相同的代码3次,所以我决定使用这样的模板重构它:

template<class _type> void myClass::do123()
{
    for( myIterator< _type > it( this->getDatabase() ); it; ++it )
    {
        do1( *it );
        do2( *it );
        do3( *it );
    }
}
void myClass::doStuffBetter()
{
    do123<Type1>();
    do123<Type2>();
    do123<Type3>();
}

还有其他更简单/更有效的方法来分解代码中的这种重复吗?

奖金问题:如果我的类型不是静态的,而是以可变参数模板给出,我将如何进行类似的处理?

3 个答案:

答案 0 :(得分:1)

您可以使用boost::mpl::vector<>作为类型列表,使用boost::mpl::for_each来迭代这些类型:

#include <boost/mpl/vector.hpp>
#include <boost/mpl/for_each.hpp>
#include <iostream>
#include <typeinfo>

struct Type1 {};
struct Type2 {};
struct Type3 {};

template<class T>
struct Type
{
    typedef T agrument_type;
};

int main(int ac, char**) {
    using Types = boost::mpl::vector<Type1, Type2, Type3>;

    boost::mpl::for_each<Types, Type<boost::mpl::_1> >([](auto type_wrapper) {
        using Type = typename decltype(type_wrapper)::agrument_type;
        // Place your code here.
        std::cout << typeid(Type).name() << '\n';
    });
}

输出:

5Type1
5Type2
5Type3

如果带有auto的C ++ 14 lambda不可用,请使用以下功能对象而不是lambda函数:

struct TypeCallback
{
    template<class TypeWrapper>
    void operator()(TypeWrapper) {
        using Type = typename TypeWrapper::agrument_type;
        // Place your code here.
        std::cout << typeid(Type).name() << '\n';
    }
};

然后:

boost::mpl::for_each<Types, Type<boost::mpl::_1> >(TypeCallback{});

如果没有使用boost,只需创建一个迭代硬编码类型列表的函数:

boost::mpl::vector<>

答案 1 :(得分:1)

这是一个C ++ 14解决方案。

namespace notstd {
  template<class T> struct tag_t { constexpr tag_t() {}; using type=T; };
  template<class T> constexpr tag_t<T> tag{};
  template<class Tag> using type_t = typename Tag::type;

  template<class...Ts, class F>
  void for_each_type(F&& f) {
    using discard=int[];
    (void)discard{ 0,(void(
      f( tag<Ts> )
    ),0)...};
  }
}

这是一些样板。

现在我们做:

void myClass::doStuffBetter()
{
  notstd::for_each_type<Type1,Type2,Type2>(
    [&](auto tag){
      using type=notstd::type_t<decltype(tag)>;
      for( myIterator<type> it( getDatabase() ); it; ++it )
      {
        do1( *it );
        do2( *it );
        do3( *it );
      }
    }
  );
}

我们可以更进一步升级myIterator<_type>,使得默认构造的实例比较等于一个过去的迭代器。

namespace notstd {
  template<class It>
  struct range_t {
    It b, e;
    It begin() const { return b; }
    It end() const { return e; }
  };

  template<class It>
  range_t<It> range( It s, It f = {} ) {
    return {std::move(s), std::move(f)};
  }
}
然后我们得到:

void myClass::doStuffBetter()
{
  notstd::for_each_type<Type1,Type2,Type2>(
    [&](auto tag){
      using type=notstd::type_t<decltype(tag)>;
      for( auto&& e : notstd::range( myIterator<type>( getDatabase() ) )
      {
        do1( e );
        do2( e );
        do3( e );
      }
    }
  );
}

答案 2 :(得分:1)

我发现你的解决方案足够好了。

为了好玩,我提出以下doStuffBetter()

template <typename ... Types>
void myClass::doStuffBetter()
 {
   int unused[] { (do123<Types>(), 0)... };

   (void)unused; // to avoid a warning
 }

应该使用C ++ 11,我想这也可以回应你的奖金问题。