这些转换中的哪一个应该是不明确的?
Which of these conversions should be ambiguous?
我有如下代码:
class bar;
class foo
{
public:
operator bar() const;
};
class bar
{
public:
bar(const foo& foo);
};
void baz() {
foo f;
bar b = f; // [1]
const foo f2;
bar b2 = f2; // [2]
}
GCC 在 [2] 而不是 [1] 处给出错误。 Clang 在两者上都给出了错误,显然 MSVC 在两者上都没有给出错误。谁说得对?
tl;博士
模棱两可。 (此外,如果您在 tl;dr 停留,那么 language-lawyer
标签可能不是您的菜。^_^)
剧透
两位候选人都有一个 const foo&
参数,它同样绑定到 const foo
或 foo
参数。没有其他规则更喜欢一个或另一个功能。
将其分解为 current C++ working draft
初始化器[dcl.init]
在这两种情况下
- 我们正在执行复制初始化([dcl.init]/15)
- 目标类型是 class 类型 ([dcl.init]/17.6)
- (X) 初始化表达式不是纯右值 ([dcl.init]/17.6.1)
- (X) 源类型与目标类型不同或派生自目标类型 ([dcl.init]/17.6.2)
- 用户定义的转换序列从[over.match.copy] and the best chosen by overload resolution中枚举。
通过用户定义的转换 class 的复制初始化 [over.match.copy]
T
是被初始化的类型,在这两种情况下都是 bar
。
S
是初始化表达式的类型,在foo
和const foo
两种情况下分别是
T
的转换构造函数是候选者 ([over.match.copy]/1.1)
bar::bar(const foo& foo);
是候选人
- 初始化表达式的类型是
_cv_ S
所以不显式 conversion functions are considered: ([over.match.copy]/1.2)
foo::operator bar() const
未隐藏在 foo
或 const foo
内,并产生 bar
与 T
相同,因此是候选者.
所以我们的候选列表在这两种情况下是相同的:
bar::bar(const foo& foo)
foo::operator bar() const
在这两种情况下,我们都有一个 user-defined conversion 包括:
- 源类型到用户定义的转换参数的标准转换
- 用户自定义转换(以上两个函数之一)到结果类型
- 结果类型到目标类型的标准转换
如果我们select构造函数,"result type"是"a prvalue of the cv-unqualified version of the destination type whose result object is initialized by the constructor"([dcl.init]/17.6.3),所以对于两个候选函数,第二个标准转换是身份 (bar
-> bar
).
过载分辨率[over.match]
对可行的候选函数进行子集化[over.match.viable]
Per [dcl.init]/17.6.3,初始化表达式将成为 selected 调用的参数,分别在 foo
和 const foo
两种情况下。
bar::bar(const foo& foo)
- 参数列表中的一个参数,正好是一个参数。 ([over.match.viable]/2.1)
- 没有关联的约束([over.match.viable]/3)
- 从
foo
和 const foo
到 const foo&
([over.match.viable]/4) 都存在隐式转换序列
- 初始标准转换在两种情况下都是身份转换:[over.best.ics]/5 => [over.ics.ref]/1用于直接引用绑定:
const foo
与 foo
和 const foo
都参考兼容,因为 const
比 const
和什么都没有。 [dcl.init.ref]/4
const foo&
直接绑定到一个左值 foo
和一个左值 const foo
。 [dcl.init.ref]/5
- 可行
foo::operator bar() const
- 参数列表中的一个参数,正好是一个隐式对象参数。 ([over.match.viable]/2.1)
- 在这两种情况下,隐式对象参数都是
const foo&
([over.match.funcs]/4)
- 没有关联的约束([over.match.viable]/3)
- 从
foo
和 const foo
到 const foo&
([over.match.viable]/4) 都存在隐式转换序列
- 初始标准转换在这两种情况下都是身份转换,见上文。
- 可行
Select最佳可行函数[over.best.ics]
两者都是Identity => User Defined Conversion => Identity,即user-defined conversion sequences.
排名转换序列over.ics.rank
我们可以建立序列之间的排名吗?仅当 one of the following applies
- (X) 不是列表初始化序列 ([over.ics.rank]/3)
- (X) 不是标准的转换序列([over.ics.rank]/3.2)
- (X) 两个序列不包含"the same user-defined conversion function or constructor or [...] initialize the same class in an aggregate initialization" ([over.ics.rank]/3.3)
转换序列无法区分,即,既不是更好也不是更坏
最佳可行函数over.match.best
这两个函数都是 'better' 函数吗?仅当 one of the following applies
- (X) 也不是更好的转换序列 ([over.match.best]/1.3)
- (X) 二次标准转换相同([over.match.best]/1.4)
- (X) 不是直接引用绑定对函数类型的引用 ([over.match.best]/1.5)
- (X) 也不是函数模板特化 ([over.match.best]/1.6 and [over.match.best]/1.7)
- (X) 两者都不受约束 ([over.match.best]/1.8)
- (X) 一个是
bar
的构造函数,但另一个不是 bar
([over.match.best]/1.9)[=206 的基数 class 的构造函数=]
- (X) 没有推导出 class 类型 ([[over.match.best]/1.10](http://eel.is/c++draft/over.match.best#1.10 and [over.match.best]/1.11
- (X) 也不是构造函数模板 ([over.match.best]/1.12)
两者都不是 'better' 函数,因此 调用格式错误 。 [over.match.best]/2
我有如下代码:
class bar;
class foo
{
public:
operator bar() const;
};
class bar
{
public:
bar(const foo& foo);
};
void baz() {
foo f;
bar b = f; // [1]
const foo f2;
bar b2 = f2; // [2]
}
GCC 在 [2] 而不是 [1] 处给出错误。 Clang 在两者上都给出了错误,显然 MSVC 在两者上都没有给出错误。谁说得对?
tl;博士
模棱两可。 (此外,如果您在 tl;dr 停留,那么 language-lawyer
标签可能不是您的菜。^_^)
剧透
两位候选人都有一个 const foo&
参数,它同样绑定到 const foo
或 foo
参数。没有其他规则更喜欢一个或另一个功能。
将其分解为 current C++ working draft
初始化器[dcl.init]
在这两种情况下
- 我们正在执行复制初始化([dcl.init]/15)
- 目标类型是 class 类型 ([dcl.init]/17.6)
- (X) 初始化表达式不是纯右值 ([dcl.init]/17.6.1)
- (X) 源类型与目标类型不同或派生自目标类型 ([dcl.init]/17.6.2)
- 用户定义的转换序列从[over.match.copy] and the best chosen by overload resolution中枚举。
通过用户定义的转换 class 的复制初始化 [over.match.copy]
T
是被初始化的类型,在这两种情况下都是 bar
。
S
是初始化表达式的类型,在foo
和const foo
两种情况下分别是
T
的转换构造函数是候选者 ([over.match.copy]/1.1)bar::bar(const foo& foo);
是候选人
- 初始化表达式的类型是
_cv_ S
所以不显式 conversion functions are considered: ([over.match.copy]/1.2)foo::operator bar() const
未隐藏在foo
或const foo
内,并产生bar
与T
相同,因此是候选者.
所以我们的候选列表在这两种情况下是相同的:
bar::bar(const foo& foo)
foo::operator bar() const
在这两种情况下,我们都有一个 user-defined conversion 包括:
- 源类型到用户定义的转换参数的标准转换
- 用户自定义转换(以上两个函数之一)到结果类型
- 结果类型到目标类型的标准转换
如果我们select构造函数,"result type"是"a prvalue of the cv-unqualified version of the destination type whose result object is initialized by the constructor"([dcl.init]/17.6.3),所以对于两个候选函数,第二个标准转换是身份 (bar
-> bar
).
过载分辨率[over.match]
对可行的候选函数进行子集化[over.match.viable]
Per [dcl.init]/17.6.3,初始化表达式将成为 selected 调用的参数,分别在 foo
和 const foo
两种情况下。
bar::bar(const foo& foo)
- 参数列表中的一个参数,正好是一个参数。 ([over.match.viable]/2.1)
- 没有关联的约束([over.match.viable]/3)
- 从
foo
和const foo
到const foo&
([over.match.viable]/4) 都存在隐式转换序列
- 初始标准转换在两种情况下都是身份转换:[over.best.ics]/5 => [over.ics.ref]/1用于直接引用绑定:
const foo
与foo
和const foo
都参考兼容,因为const
比const
和什么都没有。 [dcl.init.ref]/4const foo&
直接绑定到一个左值foo
和一个左值const foo
。 [dcl.init.ref]/5
- 可行
foo::operator bar() const
- 参数列表中的一个参数,正好是一个隐式对象参数。 ([over.match.viable]/2.1)
- 在这两种情况下,隐式对象参数都是
const foo&
([over.match.funcs]/4)
- 在这两种情况下,隐式对象参数都是
- 没有关联的约束([over.match.viable]/3)
- 从
foo
和const foo
到const foo&
([over.match.viable]/4) 都存在隐式转换序列
- 初始标准转换在这两种情况下都是身份转换,见上文。
- 可行
Select最佳可行函数[over.best.ics]
两者都是Identity => User Defined Conversion => Identity,即user-defined conversion sequences.
排名转换序列over.ics.rank
我们可以建立序列之间的排名吗?仅当 one of the following applies
- (X) 不是列表初始化序列 ([over.ics.rank]/3)
- (X) 不是标准的转换序列([over.ics.rank]/3.2)
- (X) 两个序列不包含"the same user-defined conversion function or constructor or [...] initialize the same class in an aggregate initialization" ([over.ics.rank]/3.3)
转换序列无法区分,即,既不是更好也不是更坏
最佳可行函数over.match.best
这两个函数都是 'better' 函数吗?仅当 one of the following applies
- (X) 也不是更好的转换序列 ([over.match.best]/1.3)
- (X) 二次标准转换相同([over.match.best]/1.4)
- (X) 不是直接引用绑定对函数类型的引用 ([over.match.best]/1.5)
- (X) 也不是函数模板特化 ([over.match.best]/1.6 and [over.match.best]/1.7)
- (X) 两者都不受约束 ([over.match.best]/1.8)
- (X) 一个是
bar
的构造函数,但另一个不是bar
([over.match.best]/1.9)[=206 的基数 class 的构造函数=] - (X) 没有推导出 class 类型 ([[over.match.best]/1.10](http://eel.is/c++draft/over.match.best#1.10 and [over.match.best]/1.11
- (X) 也不是构造函数模板 ([over.match.best]/1.12)
两者都不是 'better' 函数,因此 调用格式错误 。 [over.match.best]/2