【问题标题】:How to initialize template member array from constructor parameter?如何从构造函数参数初始化模板成员数组?
【发布时间】:2016-07-14 00:21:42
【问题描述】:

本质上,我想要一个模板类,其中包含一个大小为模板参数的数组,以保存常量内容。

类似:

template<size_t S> struct Foo {
    const int bar[S];
    Foo(const int(&par)[S]) : bar(par) {
        cout << "bar size is " << S << endl;
    }
};
auto foo = Foo({1,2,3});

我一直在搜索和修改,几乎有一个使用中间静态方法并使用 std::array 实现的解决方法:

template<size_t S> struct Baz {
  const array<int,S> qux;
  Baz(const array<int,S>&par) : qux(par) {
    cout << "size is " << S << endl;
  }
};
template<size_t S> Baz<S>
GetBaz(const array<int,S>&in) {
  return Baz<S>(in);
}

int main() {
  auto sample = GetBaz({1,2,3});
  return 0;
}

... 这已经是一些样板文件了,但 std::array 似乎仍然不是从初始化列表构造的? :-(

prog.cpp: In function 'int main()':
prog.cpp:27:30: error: no matching function for call to 'GetBaz(<brace-enclosed initializer list>)'
  auto sample = GetBaz({1,2,3});

【问题讨论】:

  • 你不能用内置数组做这个,必须使用std::array
  • 对于auto sample = GetBaz({1,2,3}); 它失败了,因为你需要指定GetBaz&lt;5&gt; 或其他。初始化器列表长度不是它们类型的一部分。
  • The code in this answer 可以帮助您解决问题,如果您愿意使用 GetBaz(1,2,3) 而不使用额外的大括号

标签: c++ arrays templates c++11 c++14


【解决方案1】:

不确定我是否完全理解这些问题。这就是你想要达到的目标吗?

#include <iostream>
#include <array>

template<size_t S> struct Baz {
    const std::array<int,S> qux;
    Baz(const std::array<int,S>& par) : qux(par) {
        std::cout << "size is " << qux.size() << std::endl;
    }
};

int main() {
    auto sample = Baz<5>({1,2,3}); // size = 5, values = 1, 2, 3, 0, 0
    return 0;
}

总结:

  1. 使用 std::array 而不是原始数组。
  2. 指定模板参数,例如:Baz&lt;5&gt;(...)不推导出类模板参数。

【讨论】:

  • 确切地说,我希望推断数组大小:-)。我知道类模板参数不能从构造函数推导出来,但我准备为此使用静态函数GetBaz()。我无法以好看的方式解决的问题是将初始化列表通过中间函数传递给构造函数。
【解决方案2】:

您可以使用经典的 C 数组,但使用可变参数构造函数

#include <array>
#include <cstddef>
#include <iostream>

using namespace std;

template <size_t S> struct Foo {
    const int bar[S];
    const std::array<int, S> bar2;

    template <typename ... I>
       Foo (const I & ... i) : bar {i...}, bar2 {{i...}}
    {
      cout << "bar size is " << S << " == " <<
         (sizeof(bar)/sizeof(bar[0])) << " == " << bar2.size() << endl;
    }
};

int main()
 {
   Foo<3>  foo {1,2,3};

   auto  foo2 = Foo<4>{1,2,3,4};

   return 0;
 }

【讨论】:

    【解决方案3】:

    Post-DR1591 内置数组绑定现在可以从 braced-init-list 推导出来,所以:

    template<size_t S> struct Baz {
      const array<int,S> qux;
      Baz(const array<int,S>&par) : qux(par) {
        cout << "size is " << S << endl;
      }
      Baz(const int (&par)[S]) : qux(std::experimental::to_array(par)) {}
    };
    
    template<size_t S> Baz<S>
    GetBaz(const int (&in)[S]) {
      return Baz<S>(in);
    }
    

    std::experimental::to_array 从内置的std::array 创建一个。请参阅链接的 cppreference 页面以了解实施情况。

    你可以一直使用内置数组,但它有点烦人:

    template<size_t S> struct Baz {
      const int bar[S]; 
    
      template<size_t... Is>
      Baz(const int (&par)[S], std::index_sequence<Is...>)
          : bar { par[Is]... } {}
    
      Baz(const int (&par)[S]) : Baz(par, std::make_index_sequence<S>()) {}
    };
    
    template<size_t S> Baz<S>
    GetBaz(const int (&in)[S]) {
      return Baz<S>(in);
    }
    

    【讨论】:

    • 谢谢,我不喜欢使用experimental,但您的回答非常明确并回答了问题。
    • 顺便说一句,你知道旧式数组的等价物吗?我仍然不明白为什么要添加 std::array 而不是改进已经存在的内容。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-02
    • 2021-03-26
    • 2016-11-15
    • 1970-01-01
    • 2017-02-02
    • 2021-05-05
    相关资源
    最近更新 更多