我正在阅读 this answer ,其中有以下示例:
struct R {};
struct S { S(R); };
struct T {
T(const T &); //1
T(S); //2
};
void f(T);
void g(R r) {
f({r});
}
答案与 [over.best.ics]/4 的旧版本有关,当时看起来像 this :
However, when considering the argument of a constructor or user-defined conversion function that is a candidate by [over.match.ctor] when invoked for the copying/moving of the temporary in the second step of a class copy-initialization, by [over.match.list] when passing the initializer list as a single argument or when the initializer list has exactly one element and a conversion to some class X or reference to (possibly cv-qualified) X is considered for the first parameter of a constructor of X, or by [over.match.copy], [over.match.conv], or [over.match.ref] in all cases, only standard conversion sequences and ellipsis conversion sequences are considered.
在答案中据说如果没有上面引用中突出显示的部分,f({r})
将是不明确的,因为它可以使用 T< 的第一个构造函数
(1) 或第二个构造函数 (2)。
但是,尽我所能,我看不出第一个构造函数 (1) 是一个选项。 f({r})
导致{r}
的T
的复制列表初始化。如果使用第一个构造函数,则标准允许从 r
转换为构造函数的参数类型。但是,仅进行一次转换是不够的,因为必须进行 R --> S(使用 S
的转换构造函数)
然后是 S --> T(使用 T
(2) 的转换构造函数)。而且我在标准中找不到任何允许在列表初始化的转换中进行多个用户定义转换的内容。
我可能遗漏了什么。 如果有人指出我的错误,我将不胜感激,如果我没有,我想知道标准引文中突出显示部分的目的是什么。
引用段落的当前版本要求初始化列表的唯一元素是初始化列表本身,这在上面的示例中是有意义的,如果不是 f({r})
有 f({{r}})
。在那种情况下,解释是正确的。
谢谢。
最佳答案
您的观察是正确的。即使没有强调部分,该示例也是合式的,但原因有点不同。
And I cannot find anything in the standard that allows more than one user-defined conversion in the cast of list initialization.
事实上,[over.best.ics]/4 正是禁止多个用户自定义转换的规则。考虑 (1) 被调用,那么我们必须用 r
复制初始化一个 T
类型的临时对象,它落入“或 [over.match.copy] , [over.match.conv], or [over.match.ref] in all cases”部分,因此是用户定义的转换(r -> const T&
和 r -> S
) 被禁止。因此,我们无法为 (1) 形成隐式转换序列,因此 (2) 胜出。
请注意,由于 issue 1758,强调的部分曾被删除,并由于 issue 2076 再次返回约束“初始化列表只有一个本身就是初始化列表的元素” .
关于C++ 列表初始化允许多个用户定义的转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51619955/