使用大括号括起初始化列表初始化一个类

时间:2016-08-05 10:59:06

标签: c++ c++14 initializer-list

我尝试用括号括起的初始化列表初始化类Vec,在这个最小的例子中调用:

int main()
{
    Vec<3> myVec1{{1,2,3}}; // or: myVec1({1,2,3});
    Vec<3> myVec2;
    myVec2 = {1, 2, 3};
    Vec<3> myVec3 = {1,2,3};
    return 0;
}

所有这些初始化(和分配)都应该有效。 (加上自定义默认构造函数。因此不可能使用聚合类。)

虽然我可以使用像这样的std :: initializer_list:

template <unsigned C>
struct Vec
{
    Vec(){}
    Vec(std::initializer_list<int> list)
    {
        //does not work for obvious reasons:
        //static_assert(list.size() == C, "");
    }
};

我无法静态地确保参数的数量等于我的模板参数,即{1,2,3,4}的初始化只会在运行时失败。

浏览SO,我想出了以下内容:

template <unsigned C>
struct Vec
{
    Vec(){}
    Vec(const unsigned(&other)[C]){}
    Vec& operator=(const unsigned(&other)[C]){return *this;}
};

这适用于赋值和()或{}初始化(对于myVec1) - 但是使用=(对于myVec3)初始化失败。

(GCC提供错误&#34;无法转换&#39; {1,2,3}&#39;&#39;&#39; Vec&lt; 3u&gt;&#39 ;&#34)

我不明白为什么其中一个初始化应该起作用,而不是另一个起作用。 任何其他想法如何使用括号括起初始化列表,但也确保在编译时正确的长度?

谢谢:)

2 个答案:

答案 0 :(得分:0)

初始化列表更适合于列表大小是动态的情况。在您的情况下,Vec的大小是模板参数(即静态),您可能更适合使用可变参数:

template <unsigned C>
struct Vec
{
    Vec(){}

    template<typename ... V>
    Vec(V ... args)
    {
        static_assert(sizeof...(V) == C, "");
        //...
    }
};

然后这些将起作用:

Vec<3> myVec2;
myVec2 = {1, 2, 3};
Vec<3> myVec3 = {1,2,3};

但是这个没赢,因为它明确要求std::initializer_list

Vec<3> myVec1{{1,2,3}};

答案 1 :(得分:0)

您需要两对括号:

Vec<3> myVec3 = {{1,2,3}};

当你这样做时:

Vec<3> myVec3 = {1, 2, 3};
// It is the same as (except that explicit constructor are not considered):
Vec<3> myVec3 = Vec<3>{1, 2, 3};'

基本上,编译器会查找Vec<3>的构造函数,该构造函数可以是std::initializer_list,也可以是带有3个参数的构造函数,所有参数都可以从int构造。

如果你想要一个std::array类似的结构,你需要创建你的类型an aggregate,这意味着它不应该有用户定义的构造函数:

template <unsigned N>
struct Vec {
  int data[N];
};

void f() {
  Vec<3> v1{{1, 2, 3}};
  Vec<3> v2 = {{1, 2, 3}};
}