c++ - 提取类的模板参数并迭代它们的最紧凑的方法是什么?

标签 c++ templates c++11 c++14 variadic-templates

在下面的小程序中,我展示了我目前用于提取类的模板参数并通过递归辅助函数对其进行迭代的解决方案。

我想知道是否有更简洁的方法来做到这一点,正如我在下面评论中的伪代码中所解释的那样。

template <int...Is> struct Pack {};

template <int I> struct B
{
    static void foo() { std::cout << I << "\n"; }
};

// recursive helper function, also used to extract the parameter pack arguments
template <int I, int...Is>
void foo_helper( Pack<I, Is...>&& )
{
    B<I>::foo();
    foo_helper( Pack<Is...>{} );
}

// terminate recursion
void foo_helper( Pack<>&& ) {}

struct A
{
    typedef Pack<1,3,5> ints;

    static void foo()
    {
        // this is what I do
        foo_helper(ints{});

        // this is what I would like to do, ideally in one single line
        // 1) extract the template arguments pack from ints, without creating an helper function for that
        // 2) iterate on the template arguments of the pack without a recursive helper
        // In pseudocode, something like:
        // (B<IterateOver<ArgumentsOf<ints>>>::foo());
    }
};

int main()
{
    A::foo();
}

最佳答案

如果您想进行元编程,请从类型开始。如果您需要非类型模板参数,请尽快将它们移至类型。

下面,我先取Pack<1,2,3>并将其转换为 types< std::integral_constant<int, 1>, std::integral_constant<int, 2>, std::integral_constant<int, 3> > .这是与您的整数包明显对应的类型列表。

然后,我介绍一个标签类型模板。这是一种“携带”另一种类型的类型,但它本身是无状态的。作为奖励,您可以从模板实例的值中提取类型。

第三,我编写了一个“针对每种类型”的函数,它接受一个 lambda 和一组类型,然后为每种类型调用一次 lambda,并传入一个标记类型。

在 lambda 的主体中,我们可以使用 decltype 提取传递的类型在标签变量(或辅助宏)上。

我们将它们链接在一起,从传递的标签类型中我们可以提取原始包中的整数。

结果是您可以将其注入(inject)到您的代码中:

for_each_type( [&](auto tag){
  constexpr int i = TAG_TYPE(tag){};
  // use i
}, ints_as_types_t<ints>{} );

在您的方法中间,处理“内联”整数。

如果我们只想解决您的特定问题,我们会少做一些样板文件,但我喜欢这种通用性。


template<class...>struct types{using type=types;};

template <int...Is> struct Pack {};

template<class pack> struct ints_as_types;
template<class pack>
using ints_as_types_t=typename ints_as_types<pack>::type;

template<class T, template<T...>class pack, T...ts>
struct ints_as_types<pack<ts...>> {
  using type=types<std::integral_constant<T,ts>...>;
};

现在我们可以做:

using pack = ints_as_types_t<Pack<1,2,3>>;

pack是类型列表,而不是整数列表。

现在一些 hana 风格的元编程:(使用值而不是纯类型进行元编程)

template<class T>struct tag_t{using type=T; constexpr tag_t(){};};
template<class T>constexpr tag_t<T> tag={};
template<class Tag>using type_t=typename Tag::type;
#define TAG_TYPE(...) type_t<std::decay_t<decltype(__VA_ARGS__)>>;

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

它让您可以遍历类型集合。

for_each_type( [&](auto tag){
  constexpr int i = TAG_TYPE(tag){};
  // use i
}, ints_as_types_t<ints>{} );

给你一个 lambda,它有一个 constexpr int i对于列表中的每种类型。

上面的一堆工作将您的整数列表提升为类型列表,因为仅使用类型可以减少元编程的特殊情况。你可以跳过那个提升,写一个 for_each_integer这需要 Pack<int...>直接使用更少的代码,但对我来说似乎用处不大。

关于c++ - 提取类的模板参数并迭代它们的最紧凑的方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34852224/

相关文章:

c++ - 关于链接/加载和模拟器的问题

c++ - shared_ptr 和循环引用

c++ - variadic类参数成员变量的异构存储

javascript - Beebole 的 PURE 是否有公共(public)托管 CDN?

python - 如何查看 django 模板列表中是否存在某个值。尝试使用 IN 运算符但不起作用

C++ 11 : How to write 2 template functions that differ in their return type

c++ - 从派生类将非构造函数参数变量传递给基类构造函数会导致奇怪的行为

c++ - 如何在Visual Studio/OpenGL中设置GPU

c++ - 编写死亡测试以验证 std::set_terminate 行为

c++ - 为 std::vector<double> boost 自定义验证器