11

我不明白为什么下面的代码打印struct Value而不是int(这意味着转换构造函数正在转换为Value而不是int)。(视觉 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>

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

4

2 回答 2

8

在第一个示例中,Visual Studio 不正确;这个电话是模棱两可的。C++03 模式下的 gcc 打印:

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]

当类类型的对象被直接初始化 [...] 时,重载决议选择构造函数。对于直接初始化,候选函数是被初始化对象的类的所有构造函数。

在第二个例子中,被删除的函数同样参与重载决议;they only affect compilation once overloads have been resolved, when a program that selects a deleted function is ill-formed. 标准中的激励示例是一个只能从浮点类型构造的类:

struct onlydouble {
  onlydouble(std::intmax_t) = delete;
  onlydouble(double);
};
于 2012-12-19T11:39:21.147 回答
1

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

由于您有一个内置的 copy-CTOR,我猜您的 main 等于:

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”。

于 2012-12-19T11:25:44.293 回答