【问题标题】:How to fill array with contents of a template parameter pack?如何用模板参数包的内容填充数组?
【发布时间】:2017-01-03 08:13:49
【问题描述】:

在我发现 it was not standards-compliant 之前,我已经嵌套了部分专用的模板代码,用于 VS 2015。我希望它是这样,所以我扭曲了我的代码以克服前一个问题以及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&amp; i 参数搞乱了扩展.

您将如何解决?

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

【问题讨论】:

  • 为什么需要可变参数模板,而带有初始化列表的 constexpr 构造函数就可以了?
  • 是的,我不知道你为什么不只是使用std::array,它正好支持这种语法......这不是“填充”数组,这意味着生成值;它只是从提供的值初始化它。当 C++ 标准库已经提供了您看似需要的轮子时,尝试自己重新发明它通常是个坏主意。
  • @SergeyA:你能详细说明一下吗?这是维托里奥的答案吗?抱歉,我对 C++ 的使用不如其他工具舒服。
  • @underscore_d:嗯,这是 SO 的一个最小示例,但基本上真正的用例提供了更多的 bloa...功能,而不仅仅是将一些值放在一起。

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


【解决方案1】:

在您的用例中是否可以接受不基于模板递归的解决方案? 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);
}

【讨论】:

  • 谢谢 Vittorio,这让我大开眼界。我添加了一个公共设置器,它只是执行 *this = Array(args...); 以满足我的需求。
【解决方案2】:

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

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

但我可能在这里叫错了树?

【讨论】:

    猜你喜欢
    • 2011-03-10
    • 1970-01-01
    • 2019-06-06
    • 2022-06-20
    • 1970-01-01
    • 1970-01-01
    • 2015-03-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多