3

我正在尝试实现一个 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但不是(至少,我无法弄清楚如何直接使用它):在这里,我想从一个已经存在的数组创建一个新数组,不是来自已知的整数序列。

编辑

现在我得到了无限的实例化,即使没有调用递归。这是一个简化的示例:

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]]

显然,可变参数函数不能“递归”调用其重载之一。我对吗 ?什么解决方法是可能的?

4

2 回答 2

4

你应该使用

template<size_t DIM, typename... ARGS> auto constexpr
add42(int index, array<int,DIM> intergerArray, ARGS... unpackedIntegers)

因为数组的第二个参数的类型size_t是 ,而不是int

于 2013-05-23T12:44:24.513 回答
3

不幸的是std::array::operator[]不是 constexpr

编译器选项:很简单-std=c++11

gcc <= 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);
于 2013-05-23T17:17:33.787 回答