【发布时间】:2017-08-29 09:24:02
【问题描述】:
我想写这样的东西:
template<int i> void f() {}
for (constexpr int i : {1,2,3})
{
f<i>();
}
是否可以在 constexpr 上进行迭代?
谢谢
【问题讨论】:
我想写这样的东西:
template<int i> void f() {}
for (constexpr int i : {1,2,3})
{
f<i>();
}
是否可以在 constexpr 上进行迭代?
谢谢
【问题讨论】:
正如您可能理解的那样,您不能这样做:
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;
}
除了可变参数模板,这种技术依赖于非常重要的 C++ 元编程
SFINAE 的原理和std::enable_if 的原理,
这是标准 C++ 库提供的用于利用 SFINAE 的工具。
101010 的回答展示了一种更复杂、更强大的风格 在 C++14 中可用的解决方案(并且很容易在 C++11 中实现) 如果你写一些支持样板文件)。
【讨论】:
int t[] 的初始化(C++ 的错,不是 101010 的错)周围有如此很多可怕的骇客,在我选择走这条路之前,我必须得到很多钱!
template<int First> for_each_f(); 和template<int First, int Second, int ...Rest> for_each_f();,就可以去掉enable_ifs
不,您不能在编译时使用 for 循环进行迭代。 C++中的for控制结构用于运行时控制流。
但是,您可以使用其他编译时工具。例如,在 C++ 14 中,您可以通过以下方式实现您想要的:
定义一个模板包装类来调用你的函数。
template<int i> struct wrapper { void operator()() const { f<i>(); } };
使用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()); }
然后调用为
int main() { call_times<wrapper, 42>(); }
如果 C++14 不是一个选项,您可以查看 here 了解如何实现 std::index_sequence 自己。
【讨论】:
(void) t 是干什么用的?
caller_impl函数体可以是(W<I>()(), ... );更容易理解。