问题
由于调用不明确,带和不带显式复制构造函数的版本都不是有效的C++代码。
MSVC编译器碰巧做了一些“神奇的”和非标准的事情来编译它(这是MSVC的一个常见主题)。如果您尝试任何其他主要编译器(gcc、clang、icc),请参阅实时示例
here
)他们都没能编译出来。
我不会依赖这种模棱两可的代码,即使它“工作”,因为它可能(也可能会)停止使用另一个编译器版本或不同的编译器。
这种模糊性来自于C++对潜在隐式转换序列进行排序的方式:它总是尝试进行最小数量的转换,最多是一次用户定义的转换。本标准详细描述了这一过程
[class.conv]
.
就你而言,打电话时
Date t1(cvt);
解决调用有两种方法,每种方法都只需要一个用户定义的转换(而不需要其他转换):
-
从
CVariant
到
int
(
CVariant::operator int()
),然后打电话给
Date::Date(int)
.
-
从
变异的
到
Date
(
CVariant::operator Date()
),然后调用(隐式)复制构造函数
Date::Date(const Date &)
.
解决方案
有几种方法可以解决此问题:
-
添加
explicit
关键字转换为CVariant转换之一,因此它将不再参与隐式转换。
-
指定要在调用站点进行的转换(例如。
Date t1(static_cast<Date>(cvt)
使用
CVVariant::运算符日期()
).
-
从中添加转换构造函数
变异的
到
日期
(
Date::Date(const CVariant &)
),这将使此构造函数不需要任何转换,因此编译器将首选此构造函数而不是其他两个。
如何实施方案3
请参阅完整示例
here
.
简而言之,您需要执行以下操作:
-
转发声明
变异的
因此,在中创建转换构造函数时,其名称可用
日期
-
将构造函数的声明添加到
日期
-
之后定义构造函数
变异的
已定义,因此您可以使用
Cvariant
到
日期
在构造函数的实现中
以下是代码的相关更改:
class CVariant;
class Date
{
public:
// [...]
explicit Date(const CVariant &cvt);
// [...]
};
class CVariant
{
// [...]
};
Date::Date(const CVariant &cvt) : Date(cvt.operator Date()) {}