如何用模板参数包的内容填充数组?

How to fill array with contents of a template parameter pack?

在我发现 it was not standards-compliant. I want it to be so I twisted my code to overcome the former issue and also that one 之前,我曾使用 VS 2015 嵌套部分专用模板代码,但现在遇到了困难。

使用可变参数模板和部分特化我想在编译时给定一组固定参数来填充一个数组。

我想要实现的目标也似乎与 this answer 相似,但我没能成功。

考虑以下程序:

#include <cstdlib>

template <typename T, std::size_t Size>
struct Array;

template <typename T, std::size_t Size, std::size_t Iteration, typename ...Args>
struct ArrayFiller {
    inline
    static void fill(Array<T, Size>& a, const Args&... args) {
        ArrayFiller<T, Size, Iteration, Args...>::fill_recursive(a, args...);
    }

    inline
    static void fill_recursive(Array<T, Size>& a, const T& i, const Args&... args) {
        a.data[Size - Iteration - 1] = i;
        ArrayFiller<T, Size, Iteration - 1>::fill_recursive(a, args...);
    }
};

template <typename T, std::size_t Size>
struct ArrayFiller<T, Size, 0> {
    inline
    static void fill_recursive(Array<T, Size>& a, const T& i) {
        a.data[Size - 1] = i;
    }
};

template <typename T, std::size_t Size>
struct Array {
    T data[Size];

    template <typename ...Args>
    Array(const Args&... args) {
        ArrayFiller<T, Size, Size - 1, Args...>::fill(*this, args...);
    }
};

int main() {
    Array<int, 2> c(42, -18);
    return 0;
}

...及其 g++ -std=c++14 -pedantic -Wall -Wextra 输出的开头(从版本 5.3.0 开始):

main.cpp: In instantiation of ‘static void ArrayFiller<T, Size, Iteration, Args>::fill(Array<T, Size>&, const Args& ...) [with T = int; long unsigned int Size = 2ul; long unsigned int Iteration = 1ul; Args = {int, int}]’:
main.cpp:34:54:   required from ‘Array<T, Size>::Array(const Args& ...) [with Args = {int, int}; T = int; long unsigned int Size = 2ul]’
main.cpp:39:28:   required from here
main.cpp:10:65: error: no matching function for call to ‘ArrayFiller<int, 2ul, 1ul, int, int>::fill_recursive(Array<int, 2ul>&, const int&, const int&)’
         ArrayFiller<T, Size, Iteration, Args...>::fill_recursive(a, args...);
                                                                 ^
main.cpp:14:17: note: candidate: static void ArrayFiller<T, Size, Iteration, Args>::fill_recursive(Array<T, Size>&, const T&, const Args& ...) [with T = int; long unsigned int Size = 2ul; long unsigned int Iteration = 1ul; Args = {int, int}]
     static void fill_recursive(Array<T, Size>& a, const T& i, const Args&... args) {
                 ^
main.cpp:14:17: note:   candidate expects 4 arguments, 3 provided

基本上编译器会抱怨没有匹配的函数,因为根据我的理解,参数包在我的逻辑中也被扩展了 "soon" 或 "late":const T& i 参数在递归调用中弄乱了扩展。

你会怎么解决?

我也对替代/更好/更清洁的解决方案感兴趣。

您的用例是否可以接受不基于模板递归的解决方案? wandbox link

template <typename T, std::size_t Size>
struct Array {
    T data[Size];

    template <typename ...Args>
    constexpr Array(const Args&... args) : data{args...} {

    }
};

int main() {
    Array<int, 2> c(42, -18);
    assert(c.data[0] == 42);
    assert(c.data[1] == -18);

    constexpr Array<int, 2> cc(42, -18);
    static_assert(cc.data[0] == 42);
    static_assert(cc.data[1] == -18);
}

我在这里可能偏离了目标,但基于这个要求“......我想在给定一组固定参数的情况下在编译时填充一个数组。”和这个代码:

int main() {
Array<int, 2> c(42, -18);
return 0;
}

我一直想知道这是否不能通过正常的数组声明和初始化来解决?

    int main() {
        constexpr  int c []{42, -18};
        static_assert( c[0] == 42 ) ;
        // and so on
      return 0;
    }

在对上一个答案的评论中,您提到了一些 setter?这里肯定少了什么……如果你需要像上面那样 class Array,也许最简单的方法是:

template<typename T, T ... V >
struct Array
{
  constexpr static T data_[]{ V... };
  // not strictly necessary
  constexpr static size_t size{ sizeof(data_) / sizeof(T) };
};

用法是这样的:

  // length is not required for declaration
  using int_array_of_4 = Array<int,1,2,3,4> ;
  static_assert( int_array_of_4::data_[0] == 1) ;
  // and so on

但我可能找错树了?