转换操作员 转换构造函数=不直觉的行为



我不明白为什么下面的代码打印struct Value而不是int(这意味着转换构造函数正在转换为Value而不是int)。(Visual C 2012)

为什么会发生这种情况?为什么编译器完全忽略Value(int)构造函数?

#include <iostream>
#include <type_info>
using namespace std;
struct Value { Value(int) { } };
struct Convertible
{
    template<class T>
    operator T() const
    { throw typeid(T).name(); }
};
int main()
{
    try { Value w((Convertible())); }
    catch (char const *s) { cerr << s << endl; }
}

编辑:

更奇怪的是(这次仅是C 11,在GCC 4.7.2上):

#include <iostream>
#include <typeinfo>
using namespace std;
struct Value
{
    Value(Value const &) = delete;
    Value(int) { }
};
struct Convertible
{
    template<class T>
    operator T() const
    { throw typeid(T).name(); }
};
int main()
{
    try { Value w((Convertible())); }
    catch (char const *s) { cerr << s << endl; }
}

给出:

source.cpp: In function 'int main()':
source.cpp:21:32: error: call of overloaded 'Value(Convertible)' is ambiguous
source.cpp:21:32: note: candidates are:
source.cpp:9:3: note: Value::Value(int)
source.cpp:8:3: note: Value::Value(const Value&) <deleted>

如果删除了复制构造函数,那么为什么有歧义?!

在第一个示例中,Visual Studio不正确;呼叫模棱两可。GCC在C 03模式打印:

source.cpp:21:34: error: call of overloaded 'Value(Convertible)' is ambiguous
source.cpp:21:34: note: candidates are:
source.cpp:9:5: note: Value::Value(int)
source.cpp:6:8: note: Value::Value(const Value&)

回想一下复制构造函数被隐式默认。理事段落为 13.3.1.3构造函数[over.match.ctor] 的初始化:

当类型的对象被直接定义[...]时,Ordload分辨率选择构造函数。对于直接启动,候选函数是要初始化对象类的构造函数。

在第二个示例中,删除的函数同样参与过载分辨率。当选择已删除函数的程序不正确时,仅一旦解决了过载,它们才会影响汇编。标准中的激励示例是只能从浮点类型构造的类的类别:

struct onlydouble {
  onlydouble(std::intmax_t) = delete;
  onlydouble(double);
};

我已经尝试了您的代码(仅在Visual Studio版本上)。

由于您有一个内置的复制器,我想您的主要内容等于:

int main()
{
    try { Value w((struct Value)(Convertible())); }
    catch (char const *s) { cerr << s << endl; }
}

编译器选择使用您的副本CTOR,而不是value(int)。

将其更改为:

int main()
{
    try { Value w((int)(Convertible())); }
    catch (char const *s) { cerr << s << endl; }
}

它打印了" int"。

最新更新