【发布时间】:2015-03-20 09:02:50
【问题描述】:
#include <iostream>
#include <string>
#include <initializer_list>
class A
{
public:
A(int, bool) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
A(int, double) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
A(std::initializer_list<int>) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};
int main()
{
A a1 = {1, 1.0};
return 0;
}
(这个问题是this的后续问题。)
上面的程序使用clang35 -std=c++11编译失败
init.cpp:15:14: error: type 'double' cannot be narrowed to 'int' in initializer list [-Wc++11-narrowing]
A a1 = {1, 1.0};
^~~
init.cpp:15:14: note: insert an explicit cast to silence this issue
A a1 = {1, 1.0};
^~~
static_cast<int>( )
而g++48 -std=c++11 选择一个产生警告来诊断畸形狭窄
init.cpp: In function ‘int main()’:
init.cpp:15:17: warning: narrowing conversion of ‘1.0e+0’ from ‘double’ to ‘int’ inside { } [-Wnarrowing]
A a1 = {1, 1.0};
^
init.cpp:15:17: warning: narrowing conversion of ‘1.0e+0’ from ‘double’ to ‘int’ inside { } [-Wnarrowing]
并产生结果
A::A(std::initializer_list<int>)
我的问题是A::A(std::initializer_list<int>) 是否应该是一个可行的重载。以下是我认为暗示initializer_list 重载不可行的标准引号。
来自13.3.2 [over.match.viable]
其次,要使
F成为一个可行的功能,每个功能都应存在 argument 一个转换该参数的隐式转换序列 到F的对应参数。
来自4 [conv]
表达式
e可以隐式转换为类型T如果并且 仅当声明T t=e;是良构的,对于一些发明的 临时变量t。
来自8.5.1 [dcl.init.aggr]
如果 initializer-clause 是一个表达式和一个窄化 转换需要转换表达式,程序是 格式不正确。
使用8.5.1 和4,因为以下格式不正确
std::initializer_list<int> e = {1, 1.0};
{1, 1.0} 不能隐式转换为std::initializer_list<int>。
使用来自13.3.2 的引用,难道不应该暗示A::A(std::initializer_list<int>) 在为A a1 = {1, 1.0}; 进行重载解析时不是一个可行的函数吗?找不到可行的initializer_list 构造函数,这句话不应该选择A::A(int, double)吗?
【问题讨论】:
-
8.5.1如何申请
int t = 1.0;?那不是聚合初始化,是吗? -
在帖子中指出,您链接到采用初始化列表的构造函数是非常受欢迎的。所以编译器选择初始化列表构造函数,然后尝试转换,因为它缩小了编译失败。
-
@Columbo 对不起,我没明白你的意思。另外,对于
8.5.1,我没有粘贴整个标准引用,但是由于您提到聚合初始化,我想这已经足够清楚了。 -
@NathanOliver 是的,但“强烈偏好”是 Scott Meyers 将标准放在简单的英语中。我在问它是如何遵循标准的。
-
@Pradhan 我发布了一个答案以使我的观点更清楚。
标签: c++ c++11 language-lawyer overload-resolution list-initialization