2
#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;
}

(这个问题是对此的后续。)

上面的程序无法编译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>( )

whileg++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成为一个可行的函数,每个参数都应该存在一个隐式转换序列,该序列将该参数转换为 的相应参数F

4 [conv]

当且仅当声明;时,表达式e才能隐式转换为类型 对于某些发明的临时变量,格式正确。TT t=et

8.5.1 [dcl.init.aggr]

如果初始化子句是一个表达式并且需要一个窄化转换来转换该表达式,那么程序是非良构的。

使用8.5.1and 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)吗?

4

1 回答 1

4

我相信您分析中的问题是声明

int t = 1.0;

确实是格式良好的 -显然存在从doubleto的隐式转换。int[over.ics.list]/4 也对其进行了描述:

否则,如果参数类型是std::initializer_list<X>并且初始化器列表的所有元素都可以隐式转换为 X,则隐式转换序列是将列表元素转换为 所需的最差转换X,或者如果初始化器列表没有元素,则恒等式转换。

初始化列表中的每个元素都可以隐式转换为int,因此构造函数是可行的并且可以选择。但是,只有在选择它之后,整个事情才会出现硬错误,[dcl.init.list]/(3.6):

枚举适用的构造函数,并通过重载决议(13.3、13.3.1.7)选择最佳构造函数。如果需要缩小转换(见下文)来转换任何参数,则程序格式错误。

如您所见,要调用的构造函数是在执行缩小检查之前确定的。换句话说,初始化列表构造函数的可行性不取决于任何参数的缩小。
因此,代码应该是格式错误的。

获得所需行为的一种方法是使用带有 SFINAE 的构造函数模板

template <typename T, typename=std::enable_if_t<std::is_same<int, T>{}>>
A(std::initializer_list<T>) { std::cout << __PRETTY_FUNCTION__ << std::endl; }

演示

于 2015-01-21T18:35:11.540 回答