【发布时间】:2012-02-27 17:55:17
【问题描述】:
在 C++ 标准 §13.3.1.7 [over.match.list] 中,声明如下:
在复制列表初始化中,如果选择了
explicit构造函数,则初始化格式错误。
这就是为什么我们不能这样做的原因,例如:
struct foo {
// explicit because it can be called with one argument
explicit foo(std::string s, int x = 0);
private:
// ...
};
void f(foo x);
f({ "answer", 42 });
(请注意,这里发生的情况不是转换,即使构造函数是“隐式”的,它也不会是一个转换。这是使用它的 foo 对象的初始化直接构造函数。除了std::string,这里没有转换。)
这对我来说似乎很好。隐式转换绝不会咬我。
如果{ "answer", 42 }可以初始化别的东西,编译器就不会背叛我做错事:
struct bar {
// explicit because it can be called with one argument
explicit bar(std::string s, int x = 0);
private:
// ...
};
void f(foo x);
void f(bar x);
f({ "answer", 42 }); // error: ambiguous call
没问题:调用不明确,代码无法编译,我必须明确选择重载。
f(bar { "answer", 42 }); // ok
由于明确规定了禁令,我觉得我在这里遗漏了一些东西。据我所知,列表初始化选择显式构造函数对我来说似乎不是问题:通过使用列表初始化语法,程序员已经表达了进行某种“转换”的愿望。
会出什么问题?我错过了什么?
【问题讨论】:
-
我不确定,但我认为这很合乎逻辑。调用 f({ "answer", 42 }),您可能永远不会知道您传递的是 foo,并且您尝试使用的构造函数是显式的,它强制执行显式转换。
-
@Geoffroy:如果可以从
{ "answer", 42 }传递其他内容,重载决议将是模棱两可的,因此迫使我明确类型。 -
我不明白你为什么不认为这种转换是隐式的。
-
sehe:“如果 f() 有另一个接受初始化列表的重载怎么办?”如果真的发生了怎么办? {"answer", 42} 不是初始化列表,因为元素的类型不同。因此它不能选择一个带有初始化列表的函数。
-
好的,但是无论涉及的确切步骤顺序如何,您仍然会在
f({"a",1});中隐式创建foo。你不是明确要求explicit发生不吗?
标签: c++ c++11 initializer-list explicit-constructor