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

时间:2016-08-26 15:39:41

标签: c++ recursion c++14 variadic-templates compile-time

我已经使用VS 2015嵌套了部分专用的模板代码,直到我发现it was not standards-compliant。我希望它是如此,所以我扭曲了我的代码以克服前一个问题,并且that one现在已经遇到了困难。

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

我想要达到的目标看起来与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

基本上编译器抱怨没有匹配的函数,因为据我所知,参数包在我的逻辑中“很快”或“太晚”扩展:递归调用中的const T& i参数搞砸了扩张。

你会如何解决?

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

2 个答案:

答案 0 :(得分:11)

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

  FIRAuth.auth()?.addAuthStateDidChangeListener { auth, user in
          if let user = user {
              // User is signed in.
           } else {
             // No user is signed in.
          }
    }

答案 1 :(得分:0)

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

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

在对上一个答案的评论中,您提到了一些塞特犬?这里肯定有一些遗漏...如果您需要上面的此类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

但是我可能在这里错了树吗?