我正在尝试编写一个我想在编译时评估的C ++循环。这是因为我需要使用循环变量作为模板参数来初始化类。在非常简单的情况下,它看起来像:
for (unsigned int i = 1; i < 8; i++) {
Vector<i> foo;
// do something with foo
}
经过一些类似的StackOverflow questions之后,我找到了一种递归写入静态for循环的方法。现在我的代码看起来像这样:
template <unsigned int i, unsigned int end>
struct static_for {
template <typename Lambda>
void operator()(const Lambda& function) const {
if (i < end) {
function(i);
static_for<start + 1, end>(function);
}
}
};
template <int N>
struct static_for<N, N> {
template <typename Lambda>
void operator()(const Lambda& function) const {
// This is just to avoid the unused variable warning - does nothing.
(void)function;
}
};
这完全符合预期。为了调用这个static_for
循环,我可以简单地写一下:
static_for<0, 8>()([](int size) {
// some code here.
});
然而,问题是我仍然无法在编译时评估i
。因为我无法在lambda表达式中创建模板化对象:
static_for<0, 8>()([](int size) {
Vector<size> var; // does not compile as size is not a constexpr.
});
我该如何使这项工作?我的static_for
循环将i
变量作为模板参数,在编译时可以使用它。我希望我的lambda表达式在编译时也接收这个参数(size
),而不是作为运行时变量传入。这怎么样?从概念上讲,这似乎是一种更简单和有用的语言特征。
答案 0 :(得分:1)
如果您可以使用C ++ 14,则可以将std::integral_constant
传递给通用lambda而不是int
。 gcc.godbolt.org example
template <unsigned int i, unsigned int end>
struct static_for {
template <typename Lambda>
void operator()(const Lambda& function) const {
if (i < end) {
function(std::integral_constant<int, i>{});
static_for<start + 1, end>(function);
}
}
};
static_for<0, 8>()([](auto size) {
Vector<decltype(size)::value> var; // does not compile as size is not a constexpr.
});
答案 1 :(得分:0)
我根据@Vittorio Romero的答案提出了一个不同的解决方案,它应该适用于c ++ 11和g ++ 4.9。您可以运行它here。在@Vittorio的解决方案中,由于Lambda
(请参阅注释中的示例代码)使用,您必须在块范围外定义integral_constant
函数。在我的解决方案中,您有更多 lambda 类行为。您可以在其他函数中定义您的结构,并将任意数量的参数传递给它。
[编辑]好吧,我的思维工作有点太晚了;)不幸的是,我不能提出一种 lambda-like 解决方案来在编译时工作。所以你必须在块范围之外定义 lambda 结构。您可以运行修改后的代码here。
#include <type_traits>
#include <iostream>
template <int COUNT, int MAX, typename Lambda>
struct StaticFor
{
template <typename... Args>
static void impl(Args&&... args)
{
Lambda::impl(std::integral_constant<int, COUNT>(), std::forward<Args>(args)...);
StaticFor<COUNT + 1, MAX, Lambda>::impl(std::forward<Args>(args)...);
}
};
template <int N, typename Lambda>
struct StaticFor<N, N, Lambda>
{
template <typename... Args>
static void impl(Args&&... args)
{
}
};
static const int DIM = 3;
static const int POINTS = 6;
template <int m, typename T>
T foo(T value)
{
return value * m;
}
struct IterateDim
{
template <typename D, typename P>
static void impl(D dIdx, P pIdx, float (&smpl)[POINTS][DIM])
{
smpl[P::value][D::value] = foo<D::value>(P::value);
}
};
struct IteratePoints
{
template <typename P>
static void impl(P pIdx, float (&smpl)[POINTS][DIM])
{
StaticFor<0, DIM, IterateDim>::impl(pIdx, smpl);
}
};
int main(void)
{
float table[POINTS][DIM];
StaticFor<0, POINTS, IteratePoints>::impl(table);
for (int p = 0; p < POINTS; ++p)
{
for (int d = 0; d < DIM; ++d)
{
std::cout << table[p][d] << ", ";
}
}
}