Constexpr函数用于向数组中添加整数

constexpr function to add an integer to an array

本文关键字:添加 整数 数组 函数 用于 Constexpr      更新时间:2023-10-16

我正试图实现一个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列表的末尾。当此参数列表包含数组中的所有整数时,就可以将其重新打包到一个新数组中。

但是我得到这个错误(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

显然,为了不混淆编译器,我必须提供两个函数:

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);