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

不羁的心 提交于 2019-12-22 08:09:24

问题


I had nested partially specialized template code working with VS 2015 until I discovered that it was not standards-compliant. I want it to be so I twisted my code to overcome the former issue and also that one and have now hit a hard wall.

Using variadic templates and partial specialization I would like to fill an array at compile-time given a fixed set of parameters.

What I want to achieve also seems similar to this answer but I did not manage to make it work.

Consider the following program:

#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;
}

...and the beginning of its g++ -std=c++14 -pedantic -Wall -Wextra output (as of version 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

Basically the compiler complains that there is no matching function because from what I understand the parameter pack is expanded either too "soon" or too "late" in my logic: the const T& i argument in the recursive call messes up the expansion.

How would you fix it?

I am also interested in alternate / better / cleaner solutions.


回答1:


Is a solution not based on template recursion acceptable in your use case? 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);
}



回答2:


I might be off target here but based on this requirement "... I would like to fill an array at compile-time given a fixed set of parameters." and this code:

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

I have been left wondering is this not solvable with a normal array declaration and initialization?

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

In a comment to the previous answer, you are mentioning some setter? There must be something missing in here... In case you need to have this class Array as above, perhaps the simplest way to do so is this:

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

Usage is this:

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

But I might be barking on the wrong tree here?



来源:https://stackoverflow.com/questions/39169965/how-to-fill-array-with-contents-of-a-template-parameter-pack

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!