用constexpr迭代

时间:2017-04-04 09:07:45

标签: c++ c++11

我想写类似的东西:

template<int i> void f() {}

for (constexpr int i : {1,2,3})
{
    f<i>();
}

是否可以迭代constexpr?

谢谢

2 个答案:

答案 0 :(得分:6)

正如您可能理解的那样,您不能这样做:

for (constexpr int i : {1,2,3})
{
    f<i>();
}

因为,如果i在循环中从1变为3,那么它是变量并且 不是编译时常量。变量不能是模板参数, 与f<i>中一样:只有编译时常量可以是模板参数。

在C ++ 11及更高版本中,感谢variadic templates, 您可以有效地迭代编译时常量的任意序列 通过使用接受合适的任意序列的模板函数的编译时递归 模板参数。

如果您还不知道怎么做,那对您来说几乎没有任何意义。 这是一个C ++ 11示例,它可以表达您想要表达的内容:

#include <type_traits>
#include <iostream>

template<int i> void f()
{
    std::cout << i << '\n';
}

// This overload is chosen when there is only 1 template argument.
template<int First, int ...Rest>
typename std::enable_if<sizeof...(Rest) == 0>::type
for_each_f()
{
    f<First>();
}

// This overload is chosen when there is > 1 template argument.
template<int First, int ...Rest>
typename std::enable_if<sizeof...(Rest) != 0>::type
for_each_f()
{
    f<First>();
    for_each_f<Rest...>();
}

int main()
{
    for_each_f<2,3,5,7,11>();
    return 0;
}

See it live

除了可变参数模板,这种技术依赖于非常重要的C ++元编程 SFINAE的原则和std::enable_if的原则, 这是标准C ++库为利用SFINAE提供的工具。

101010的回答展示了一种更为复杂和强大的风格 C ++ 14中提供的解决方案(并且很容易在C ++ 11中实现) 如果你写一些支持样板文件。)

答案 1 :(得分:5)

不,你不能在编译时使用for循环进行迭代。 C ++中的for控制结构用于运行时控制流程。

但是,您可以使用其他编译时工具。例如,在C ++ 14中,您可以通过以下方式实现所需:

  1. 定义一个模板包装器类,它将调用您的函数。

    template<int i>
    struct wrapper {
      void operator()() const { f<i>(); }
    };
    
  2. 使用std::index_sequence生成编译时索引。

    template<template<int> class W, std::size_t... I>
    void caller_impl(std::index_sequence<I...>) {
      int t[] = { 0, ((void)W<I>()(), 1)... };
      (void) t;
    }  
    
    template<template<int> class W, std::size_t N, typename Indices = std::make_index_sequence<N>>
    void call_times() {
      caller_impl<W>(Indices());
    }
    
  3. 然后拨打

    int main() {
      call_times<wrapper, 42>();
    }
    

    Live Demo

  4. 如果C ++ 14不是一个选项,您可以查看here如何实现自己的std::index_sequence