构造函数和initializer_list

时间:2013-04-07 06:00:54

标签: c++ c++11 g++ initializer-list

有人可以告诉我这背后的理论吗?

为什么最后一次调用无法编译?

  

test.cc:在函数'int main()'中:test.cc:15:12:错误:'int'初始化器周围有太多括号[-fpermissive] test.cc:15:12:

     

错误:从''转换为'int'无效转换[-fpermissive] test.cc:9:6:错误:初始化'void f(std :: initializer_list)'[-fpermissive] test.cc的参数1: 15:12:

     

错误:在预期整数时使用的聚合值

我认为c ++ 11或g ++ 4.7在这方面是打破的。 谢谢!

#include <initializer_list>

class A { 
  public:
  A(const std::initializer_list<int>) {}
};

void f(const std::initializer_list<int>) {}

int main() {
  A({1});  // Compile OK
  f({1});  // Compile OK
  A({{{1}}});   // Compile OK
  //f({{{1}}}); // Compile Error.
}

2 个答案:

答案 0 :(得分:2)

以下是我认为GCC的想法。

这是你的程序,有1个额外的行,有趣的行编号。

int main() {
  A({1});  // 1. Compile OK
  f({1});  // 2. Compile OK
  AA a{A};   // 4a. Compile OK
;  // 3. Compile OK, equivalent to 1. 
  A({AA
});   // 4. Compile OK
  //f({class A { 
    public:
    explicit A(const std::initializer_list<int> il) {}
};
}); // 5. Compile Error.
}

为什么GCC编译4而不是5?

为清楚起见,假设#4的构造实际上声明了一些东西:

error: converting to ‘A’ from initializer list would use explicit constructor ‘A::A(std::initializer_list<int>)’

GCC询问构造函数的参数是否为{{1}} 隐式可转换为{{1}}。所以是:

{{1}}

从{{1}}到{{1}}的有效转换?是的 - 按照3。

这种推理当然不适用于#5;因此错误。

如果你想阻止GCC接受#4,那么阻止 通过使启用构造函数显式启用转换:

{{1}}

然后#4将给出错误:

{{1}}

答案 1 :(得分:2)

{1}可以初始化int。一个{{1}}可能不应该 - 有一个关于委员会的缺陷报告。海湾合作委员会禁止这样做,并且铿锵声往往会发出有关多余支撑的警告。

当X是具有复制或移动构造函数的类时,X({...})可以调用它们中的一个。请注意,X {...}也可以,但仅限于不允许用户定义的转换(对于复制或移动构造函数)。

现在使用你的A({{{1}}}),第一个括号被复制/移动构造函数使用。第二个递归地转到初始化列表。第三个进入包含的int。

根据标准,添加一个大括号将打破A({{{{1}}}})。因为第二个大括号需要由A的复制/移动构造函数使用,但需要用户定义的转换序列。 A {{{{1}}}}同样适用,因此也无效。