I tried to code a basic, compile-time version of std::accumulate()
by defining a class template that would recursively iterate through a given range and would add the elements at each iteration.
When compiling a test program using gcc 4.8.4
on Ubuntu 14.04
, I get the following error:
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;
Here's the code:
#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;
}
So basically, the standard doesn't allow the use of variables in template arguments, which is what I'm doing here:
const int a = accumulator<int,
decltype(v.cbegin()),
v.cbegin(),
4,
0>::value;
Q: What is the proper method for coding a class template (or any other "compile-time" computation mechanism) for achieving a similar result to std::accumulate()
?
(Ideally, one should be able pass custom ranges and binary operations like the real std::accumulate()
)
EDIT: The std::vector
used in the code is just an example. I've also tried std::array
and C-style arrays but I still had similar problems.
EDIT2: I don't want to use macros.
EDIT3: I don't want to use external libraries. The goal here is to do a simple, self-contained compile-time computation block. Class template was the my first idea, but I'm open to other suggestions/techniques.
std::vector
storage is allocated during runtime. Thus, is not possible to iterate through astd::vector
during compile time. – Glomerationstd::array
as it's size is known at compile time. You cannot do that forstd::vector
– Swordfishaccumulate
is also provided. – Trichinize