3

在标准文本中有一个例子在8.5.4 (3) List-initialization [dcl.init.list]

struct S {
    S(std::initializer_list<double>);  // #1
    S(const std::string&);             // #2
};
const S& r1 = { 1, 2, 3.0 };  // OK: invoke #1
const S& r2 { "Spinach" };    // OK: invoke #2 !!!

(这个例子是关于 ref-to-temp,但我在这里指的是重载解决方案)。

而斯科特迈耶斯在他的演讲/幻灯片中讲述了一个不同的故事:

std::initializer_list 参数总是优先于其他类型:

class Widget {
public:
    Widget(double value, double uncertainty);           // #1
    Widget(std::initializer_list<std::string> values);  // #2
};
double d1, d2;
Widget w1 { d1, d2 }; // tries to call #2; fails because
                      // no double ⇒ string conversion

这些例子略有不同,但不是同一件事吗?何时以及如何使用initializer_list-constructors 进行重载解析?还是这里有不同的问题?

两种情况下的超载是如何决定的?如果两者都是正确的,我在这里错过了什么?

编辑/澄清Keric评论:我的感觉是,这两个例子相互矛盾:

  • Std 给出了一个示例,其中 aconst char*转换为 a string,它与提供的不匹配initializer_list<int>,因此使用提供的“正常” const string&-c'tor。
  • Scott 的示例在-c'tor 可用并因此被选择{double, double}时进行初始化,因为他认为该列表是首选。intializer_list<int>因此,以(double, double)这种方式初始化时,永远不会选择还提供的 -c'tor。

当然,Std 总是正确的,但也许我错误地应用了这个例子。Std 示例&中有,我认为这与我的问题无关,但也许我错了。

Scott 的幻灯片是最新的,我看不到标准中的相关部分已经改变到这方面(尽管很难将所有内容都纳入范围,因为它有点“广泛传播”:-)

编辑 2:我收到了 Scott 本人的一封邮件,说标准中有一个后期更改尚未纳入幻灯片。

4

1 回答 1

5

根据 2011 年 4 月 5 日的工作草案 N3291,初始化列表有一些更改,因此 Scott Meyer 的幻灯片可能来自旧数据。

根据第 13.3.1.7 节(如此接近 1337):

  • 最初,候选函数是类 T 的初始化器列表构造函数(8.5.4),参数列表由初始化器列表作为单个参数组成
  • 如果没有找到可行的初始化列表构造函数,则再次执行重载决议,其中候选函数是类 T 的所有构造函数,参数列表由初始化列表的元素组成。

所以它确实更喜欢初始化器列表。但是如果初始化列表不匹配,那么它将检查常规构造函数以查看它们是否匹配。

它继续说,如果初始化列表为空,则使用默认构造函数。

于 2011-07-19T11:07:02.940 回答