【发布时间】:2015-10-15 20:16:32
【问题描述】:
我尝试编写一个基本的编译时版本的std::accumulate(),方法是定义一个类模板,该模板将递归迭代给定范围并在每次迭代时添加元素。
在Ubuntu 14.04 上使用gcc 4.8.4 编译测试程序时,出现以下错误:
compile-time-accumulate.cpp: In function ‘int main()’:
compile-time-accumulate.cpp:44:40: error: call to non-constexpr function ‘std::vector<_Tp, _Alloc>::const_iterator std::vector<_Tp, _Alloc>::cbegin() const [with _Tp = int; _Alloc = std::allocator<int>; std::vector<_Tp, _Alloc>::const_iterator = __gnu_cxx::__normal_iterator<const int*, std::vector<int> >; typename __gnu_cxx::__alloc_traits<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type>::const_pointer = const int*]’
v.cbegin(),
^
compile-time-accumulate.cpp:46:32: error: ‘class __gnu_cxx::__normal_iterator<const int*, std::vector<int> >’ is not a valid type for a template non-type parameter
0>::value;
代码如下:
#include <iostream>
#include <vector>
template
<
typename ResultType,
typename IteratorType,
IteratorType Iterator,
int RangeLength,
ResultType InitialValue
>
struct accumulator
{
static_assert(RangeLength > 1, "The range length must be > 1");
static constexpr ResultType value = InitialValue
+ accumulator<ResultType,
IteratorType,
Iterator + 1,
RangeLength - 1,
*Iterator>::value;
};
template
<
typename ResultType,
typename IteratorType,
IteratorType Iterator,
//int RangeLength,
ResultType InitialValue
>
struct accumulator<ResultType, IteratorType, Iterator, 1, InitialValue>
{
static constexpr ResultType value = InitialValue + *Iterator;
};
int main()
{
std::vector<int> v = {4,5,6,7};
const int a = accumulator<int,
decltype(v.cbegin()),
v.cbegin(),
4,
0>::value;
std::cout << a << std::endl;
}
所以基本上,标准不允许在模板参数中使用变量,这就是我在这里所做的:
const int a = accumulator<int,
decltype(v.cbegin()),
v.cbegin(),
4,
0>::value;
问:编写类模板(或任何其他“编译时”计算机制)以实现与std::accumulate() 类似的结果的正确方法是什么?
(理想情况下,应该能够像真正的std::accumulate() 一样传递自定义范围和二进制操作)
编辑: 代码中使用的std::vector 只是一个示例。我也尝试过 std::array 和 C 样式的数组,但我仍然遇到类似的问题。
EDIT2:我不想使用宏。
EDIT3:我不想使用外部库。这里的目标是做一个简单的、自包含的编译时计算块。类模板是我的第一个想法,但我愿意接受其他建议/技术。
【问题讨论】:
-
std::vector存储在运行时分配。因此,在编译期间不可能遍历std::vector。 -
如果您使用 integer_sequence 而不是向量,我认为您可以更轻松地完成此操作。
-
你可以遍历
std::array,因为它的大小在编译时是已知的。std::vector你不能这样做 -
有一组 constexpr 容器here;还提供了
accumulate。
标签: c++ templates c++11 template-meta-programming gcc4.8