繁体   English   中英

constexpr函数向数组添加整数

[英]constexpr function to add an integer to an array

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

编辑

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

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

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

你应该用

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

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

不幸的是, 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);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM