C ++转换运算符与构造函数优先级,编译器不同

时间:2014-06-06 20:04:15

标签: c++ gcc casting

我有2个非常简单的类,ClassA和ClassB。我希望能够从ClassB转换为ClassA。使用Sun C ++ 5.11,它可以很好地编译并按照我的预期运行,根据这个:Conversion constructor vs. conversion operator: precedence

当我尝试使用gcc版本4.8.2编译它时,它给出了一个关于对重载函数的模糊调用的错误。当铸造似乎是一个相当明确的行为时,为什么这会表现不同?

守则

main.cc

#include <iostream>

class ClassB;

class ClassA
{
    public:
    ClassA( const int& num )
    : _number( num )
    { std::cout << "ClassA int constructor\n"; }

    private:
    int _number;
};

class ClassB
{
    public:
    ClassB( const int& num )
    : _number( num )
    { std::cout << "ClassB int constructor\n"; }

    operator ClassA() const throw()
    {
        std::cout << "ClassB operator ClassA()\n";
        return ClassA( _number );
    }
    operator int() const throw()
    {
        std::cout << "ClassB operator int()\n";
        return _number;
    }

    private:
    int _number;
};

int main( int argc, const char* argv[] )
{
    std::cout << "Creating b:\n";
    ClassB b( 5 );
    std::cout << "Casting b to a ClassA:\n";
    ClassA a = static_cast<ClassA>( b );
}

使用Sun C ++ 5.11,它可以很好地编译并吐出以下输出:

Creating b:
ClassB int constructor
Casting b to a ClassA:
ClassB operator ClassA()
ClassA int constructor 

使用gcc,编译器会发出以下错误:

main.cc: In function 'int main(int, const char**)':
main.cc:43:36: error: call of overloaded 'ClassA(ClassB&)' is ambiguous
  ClassA a = static_cast<ClassA>( b );
                                    ^
main.cc:43:36: note: candidates are:
main.cc:8:2: note: ClassA::ClassA(const int&)
  ClassA( const int& num )
  ^
main.cc:5:7: note: ClassA::ClassA(const ClassA&)
 class ClassA

如果我注释掉ClassB :: operator int()或ClassA :: ClassA(const int&amp;),它会编译好并提供相同的输出。如果我注释掉ClassB :: operator CLassA(),我得到以下输出:

Creating b:
ClassB int constructor
Casting b to a ClassA:
ClassB operator int()
ClassA int constructor

为什么gcc认为这两个转换序列是等价的:

  

ClassB :: operator ClassA()
  ClassB :: operator int() - &gt; ClassA :: ClassA(const int&amp;)

2 个答案:

答案 0 :(得分:4)

如果您的编译器支持C ++ 11功能,您可以明确声明转换运算符:

class ClassB
{
    public:
    explicit ClassB( const int& num );

    explicit operator ClassA() const throw();
    explicit operator int() const throw();
    explicit operator float() const throw();

    int getNumber() const;

    private:
    int _number;
}

Display

因此,编译器不会因为模糊调用而在重载决策中感到困惑 由于隐式转化,static_cast<>必须选择。

答案 1 :(得分:1)

这应该有效:

int main( int argc, const char* argv[] )
{
    std::cout << "Creating b:\n";
    ClassB b( 5 );
    std::cout << "Casting b to a ClassA:\n";
    ClassA a = b.operator ClassA();
}

这里发生的事情是static_cast在您的各种转换运算符之间混淆了。它试图从ClassA到ClassB,但由于C ++允许在函数调用中进行一次隐式转换,并且有多个可能的转换路径(ClassB要浮动到ClassA,ClassB要转换为int到ClassA,ClassB直接转换为ClassA),编译器会抱怨关于歧义。 (好吧,在你编辑浮动路径之前......)

直接调用所需的转换运算符可以解决歧义,因为不再存在任何潜在的隐式转换。

编辑:下面的两个答案(在转换运算符上使用explicit)也很好地删除了模糊路径,同时仍允许直接转换。这可能是你想要的方式。

相关问题