我知道 C++ 在类型之间进行转换时只允许单个用户定义的隐式转换。然而,我最近遇到了一种情况,似乎在初始化时允许双重用户定义的隐式转换。 考虑以下课程:
//fractions
class Rational {
public:
int num, den;
// default constructor, etc.
Rational(int n) : num(n), den(1) {} // NOT explicit
// arithmetic and compound assignment defined between two Rational's.
};
//numbers of the form a + b sqrt(N), where a, b are of type R
template<typename R, int N>
class RingExtension {
public:
R a, b;
// default constructor, etc.
RingExtension<R, N>(R a) : a(a), b(0) {} // NOT explicit
// arithmetic and compound assignment defined between two RingExtension<R, N>'s.
};
正如预期的那样,以下内容将无法编译:
int main() {
RingExtension<Rational, 2> x;
x /= 3; // ERROR! Can't do the conversion int -> Rational -> RingExtension<Rational, 2>
x /= (Rational)3; // this does work
}
但是,以下确实
可以在 Visual Studio 2013 中编译:
int main() {
RingExtension<Rational, 2> x = 3; // int -> Rational -> RingExtension<Rational, 2>
}
为什么后一种情况允许双重用户定义转换?在这种特殊情况下,Visual Studio 是否不符合标准?或者初始化标准有什么例外吗?
编辑:正如 Kerrek SB 建议的那样,我已经通过 Wandbox 在 clang 和 gcc 中测试了我的代码。正如人们所期望的那样,两个编译器都会在初始化时抛出错误。问题仍然存在,谁错了?看起来 Visual Studio 太宽松了,但如果有人能证实这一点那就太好了。
编辑:这些类的完整源代码,包括 main() 函数,可以在这里找到:
http://pastebin.com/JNSvkwi0#或
/std:c++20
(默认情况下启用 /permissive-
)来禁用。我找不到更窄的/Zc:
选项。我也无法找到有关此问题的 Microsoft 文档。但是,即使在其版本 2017.2中也存在相应的 JetBrains ReSharper 警告:
在复制初始化期间应用了多个隐式转换。这是非标准的 Microsoft C++ 扩展评论中指向 connect.microsoft.com 的链接不幸的是,
现已失效,我无法在 Visualstudio.com 上找到相应的主题。因此,作为预防措施,我已将此答案中的所有其他链接添加到 https://web.archive.org/。