【问题标题】:Conversion operator + conversion constructor = unintuitive behavior?转换运算符 + 转换构造函数 = 不直观的行为?
【发布时间】:2012-12-19 10:43:21
【问题描述】:

我不明白为什么下面的代码打印的是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; }
}

编辑:

更奇怪的是this(这一次它只是 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>

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

【问题讨论】:

  • 为什么会打印int?您正在尝试创建Value 的实例,因此您将转换为Value
  • @R.MartinhoFernandes:我在调用Value的构造函数,它的参数类型是int,那为什么Convertible()不被转换成int呢?为什么隐式复制构造函数完全隐藏了我显式定义的构造函数,而不是导致歧义错误?
  • liveworkspace.org/code/3ZUTMY$0 ...您使用哪个编译器?
  • @Mehrdad 它将被转换为int,然后转换为Value
  • 我现在明白了这个问题,但是你所说的“奇怪”是正常的:删除的函数不会从重载决议中删除。如果他们被选中,他们只会使程序格式错误。这是一个功能。

标签: c++ visual-c++ implicit-conversion


【解决方案1】:

在第一个示例中,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 Initialization by constructor [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);
};

【讨论】:

    【解决方案2】:

    我已经尝试过您的代码(仅适用于 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”。

    【讨论】:

    • 再看第一个代码sn -p。 OP定义了他们自己的c'tor。所以应该没有copy-c'tor。
    • @DimaRudnik - 是的,如果您自己没有实现一个默认的复制 c'tor。
    猜你喜欢
    • 2021-12-04
    • 2010-11-25
    • 1970-01-01
    • 1970-01-01
    • 2020-06-12
    • 2018-08-12
    • 1970-01-01
    • 1970-01-01
    • 2012-09-02
    相关资源
    最近更新 更多