这个问题可能被认为是理论上的,因为我不明白为什么在实际代码中会有这样的设计。我有两个带有一些转换运算符的类:
class B;
class A {
public:
A() = default;
A(B const &);
};
class B {
public:
B() = default;
operator A();
};
A::A(B const &) {};
B::operator A() { return A{}; };
int main() {
[[maybe_unused]] A ad{B{}}; // direct init
[[maybe_unused]] A ac = B{}; // copy init
}
仅使用 gcc 并且仅使用复制初始化我收到此警告:
警告:选择“B::operator A()”而不是“A::A(const B&)”[-Wconversion]
警告:从“B”到“A”的转换 [-Wconversion]
注意:因为参数的转换顺序更好
由于不熟悉转换规则,我不明白这个警告是否相关?如果不相关,如何才能让它保持沉默(这可能会很痛苦-Werror
)?
NB:添加一些跟踪后,我观察到根据编译器和初始化性质的不同行为。转换序列是否在某种程度上依赖于实现?
(虽然不是 100% 确定的答案,但我不确定是否有可能。)
这里的复杂性部分在于您的
operator A()
不是 const 成员函数。因此,我们可以在采用 non-const 的转换函数this
和采用 const 的转换构造函数之间进行选择this
(在这种情况下,匹配稍差,因为您的输入B
prvalue 是 non-const)。戈德博特:
如果您这样做
B::operator A() const
,那么大多数编译器都会调用return b
ambiguous(Godbolt),但仍然允许return A(b)
。这基本上是CWG 2327的主题;另请参见从 C++14 到 C++17,转换运算符相对于复制构造函数的偏好发生了变化?和在重载解析期间在 c++17 中调用转换运算符而不是转换构造函数。
至于为什么 Clang 更喜欢转换函数而不是转换构造函数,我并不是 100% 确定,但似乎Clang 错误 #89501可能与之有关。听起来当前的行为只是偶然发生的,不一定是设计使然;但他们不打算在 CWG 2327 得到解决之前触及它。