我正在尝试实现一个constexpr函数“add42”,这将允许我这样做:
constexpr array<int,5> arr = {1,2,3,4,5};
constexpr array<int,5> arr2 = add42(0,arr); //I want arr2=={43,2,3,4,5}
即,将给定索引处的整数静态地添加到数组(使用constexpr)。 由于我的数组“arr”是不可变的,我实际上必须从“arr”和我的索引创建一个新的。这就是我编写这个函数的原因:
template<int DIM, typename... ARGS> auto constexpr
add42(int index, array<int,DIM> intergerArray, ARGS... unpackedIntegers) -> array<int,DIM> {
return
( sizeof...(ARGS)==DIM ) ?
array<int,DIM>( {{unpackedIntegers...}} ) :
( (sizeof...(ARGS)-1)==index ) ?
add42(index, intergerArray, unpackedIntegers..., intergerArray[sizeof...(ARGS)-1]+42 ) :
add42(index, intergerArray, unpackedIntegers..., intergerArray[sizeof...(ARGS)-1] ) ;
}
也就是说,我的数组的所有整数都是从数组中递归解压缩的,如果在正确的索引处添加了42,并且在ARGS列表的末尾附加了。当这个arg列表包含数组中的所有整数时,我们就完成了,所以我们可以重新打包成一个新的数组。
但是我收到了这个错误(gcc 4.7.2)
error: no matching function for call to 'add42(int, const std::array<int, 5u>&)'|
note: candidate is:|
template<int DIM, class ... ARGS> constexpr std::array<int, DIM> add42(int, std::array<int, DIM>, ARGS ...)|
note: template argument deduction/substitution failed:|
note: mismatched types 'int' and '#'integer_cst' not supported by dump_type#<type error>'|
你能解释一下我的问题是什么以及如何纠正它?
这个问题看起来与C++11: Compile Time Calculation of Array类似,但不是(至少,我无法弄清楚如何直接使用它):在这里,我想从已经存在<创建一个新数组/ strong>一,不是来自已知的整数序列。
修改
现在我得到了无限的实例化,即使没有调用递归也是如此。这是一个简化的例子:
template<size_t DIM, typename... ARGS> auto constexpr
add42(int index, array<int,DIM> integerArray, ARGS... unpackedIntegers) -> array<int,DIM> {
return
( true ) ?
array<int,DIM>( {{unpackedIntegers...}} ) :
add42(index, integerArray, unpackedIntegers..., integerArray[(sizeof...(ARGS)-1)] ) ;
}
为什么我的编译器会尝试编译最后一个函数调用?
编辑2
显然,我必须提供2个函数,以免混淆编译器:
template<size_t DIM, class... ARGS> constexpr auto
add42(int index, array<int,DIM> integerArray, ARGS... unpackedIntegers) -> typename enable_if<sizeof...(ARGS)==DIM ,array<int,DIM>>::type
{
return array<int,DIM>( {{unpackedIntegers...}} );
}
template<size_t DIM, class... ARGS> constexpr auto
add42(int index, array<int,DIM> integerArray, ARGS... unpackedIntegers) -> typename enable_if<sizeof...(ARGS)!=DIM ,array<int,DIM>>::type
{
return
( sizeof...(ARGS) == index ) ?
add42(index, integerArray, unpackedIntegers..., integerArray[sizeof...(ARGS)]+42) :
add42(index, integerArray, unpackedIntegers..., integerArray[sizeof...(ARGS)]) ;
}
但它仍然不起作用:
recursively required from [[name of the second function]]
显然,可变参数函数不能“递归地”调用其重载之一。 我对吗 ?可能的解决方法是什么?
答案 0 :(得分:4)
你应该使用
template<size_t DIM, typename... ARGS> auto constexpr
add42(int index, array<int,DIM> intergerArray, ARGS... unpackedIntegers)
因为数组的第二个参数的类型为size_t
,而不是int
。
答案 1 :(得分:3)
不幸的是,std::array::operator[]
不是 constexpr
。
编译器选项:只是简单-std=c++11
gcc&lt; = 4.6:-std=c++0x
并将using
指令替换为typedef
#include <cstddef>
//#include <array>
#include <type_traits>
#include <iostream>
template < typename T, std::size_t dim >
struct c_array
{
T arr[dim];
constexpr T operator[](std::size_t index)
{ return arr[index]; }
T const* begin() const
{ return arr; }
T const* end() const
{ return arr+dim; }
};
// I like the overloaded version better (instead of enable_if) :)
template < typename T, std::size_t dim, typename... TT >
constexpr c_array<T, dim>
add_to(T s, c_array<T, dim> in, std::size_t index, std::true_type, TT... pp)
{
return {{pp...}};
}
template < typename T, std::size_t dim, typename... TT >
constexpr c_array<T, dim>
add_to(T s, c_array<T, dim> in, std::size_t index, std::false_type, TT... pp)
{
using test = std::integral_constant<bool, (sizeof...(pp)+1 == dim)>;
return index == sizeof...(pp)
? add_to(s, in, index, test{}, pp..., in[sizeof...(pp)]+s)
: add_to(s, in, index, test{}, pp..., in[sizeof...(pp)] );
}
// unfortunately, I don't know how to avoid this additional overload :(
template < typename T, std::size_t dim>
constexpr c_array<T, dim>
add_to(T s, c_array<T, dim> in, std::size_t index)
{
return add_to(s, in, index, std::false_type{});
}
constexpr c_array<int,5> arr = {1,2,3,4,5};
constexpr c_array<int,5> arr2 = add_to(42, arr, 0); //I want arr2=={43,2,3,4,5}
int main()
{
for(auto const& e : arr2)
{
std::cout << e << ", ";
}
}
替代版本,略显笨拙的使用语法:
// helper; construct a sequence of non-type template arguments
template < std::size_t... tt_i >
struct seq
{};
template < std::size_t t_n, std::size_t... tt_i >
struct gen_seq
: gen_seq < t_n-1, t_n-1, tt_i...>
{};
template < std::size_t... tt_i >
struct gen_seq < 0, tt_i... >
: seq < tt_i... >
{};
template < std::size_t index, typename T, std::size_t dim,
std::size_t... tt_bef, std::size_t... tt_aft >
constexpr c_array<T, dim>
add_to(T s, c_array<T, dim> in, seq<tt_bef...>, seq<tt_aft...>)
{
return {{ in[tt_bef]..., in[index]+s, in[tt_aft]... }};
}
template < std::size_t index, typename T, std::size_t dim >
constexpr c_array<T, dim>
add_to(T s, c_array<T, dim> in)
{
return add_to<index>(s, in, gen_seq<index>{}, gen_seq<dim-index-1>{});
}
constexpr c_array<int,5> arr = {1,2,3,4,5};
constexpr c_array<int,5> arr2 = add_to<0>(42, arr);