【问题标题】:type conversion operator not being used to cast, compilers differ类型转换运算符不用于强制转换,编译器不同
【发布时间】:2014-05-23 18:33:52
【问题描述】:

当从一个类转换到另一个类时,C++ 编译器如何决定使用哪个类型转换运算符或构造函数?为什么这种行为会在编译器之间发生变化?

编辑:B::operator ClassA() 应该是公共的,固定的。

EDIT2:经过进一步调查,我认为我正在取得一些进展:

第一个示例代码的完整错误信息如下:

file1.cc:123:45 error: call of overloaded 'ClassA(ClassB&)' is ambiguous  
someFunction( ( (ClassA) cbObject ).methodOfClassA() )  

file1.cc:123:45 notes: candidates are:  
In file included from ...:  
/path/to/file/class_a.hh:123:4: note: ClassA::ClassA( some_type )  

/path/to/file/class_a.hh:133:4: note: ClassA::ClassA( some_other_type )

重要的部分是 ClassB 还具有 some_type 和 some_other_type 的类型转换运算符。如果我注释掉 some_type 的类型转换运算符,编译器将不再将其列为 ClassA(ClassB&) 调用的候选对象。

这意味着编译器正在使用 ClassB 的运算符将 ClassB 转换为某个中间类型,然后使用该类型调用 ClassA 的构造函数,而不是使用 ClassB 的运算符 ClassA()。我仍然不确定为什么......

EDIT2 结束

我正在尝试将一些为 Solaris 编写的代码移植到 Linux 上。它在 Solaris 上编译和运行良好,但在 Linux 上出现一些编译器错误。

Solaris 编译器:CC:Sun C++ 5.11
Linux编译器:gcc 4.8.2版

下面是相关代码:

class_a.hh

class ClassA
{
    public:
    // Several constructors, none of which take a ClassB
    ClassA( some_type source )
    ...

    ClassA( some_other_type source )
    ...
}

class_b.hh

class ClassB
{
    public:
    // constructors and such
    ...

    virtual operator ClassA() const throw();
    ...
}

class_b.cc

ClassB::operator ClassA() const throw()
{
    ClassA newClassA;
    // logic to initialize classA with classB's data
    return newClassA;
}

使用这些类的代码中充斥着从 ClassB 到 ClassA 的转换。一些例子:

ClassB cbObject;
// cbObject is initialized with data somehow
someFunction( ( (ClassA) cbObject ).methodOfClassA() )  

或将 ClassB 传递给采用 ClassA 的函数

int someOtherFunction( ClassA caObject )
{
    ...
}    
...
ClassB cbObject;
// cbObject initialized with data somehow
int someNumber = someOtherFunction( cbObject ); 

再一次,在 Solaris 上,这一切都可以正常编译和运行,并且符合预期。但是,在 Linux 上,我收到如下错误:

对于第一个示例代码,我收到此错误:

file1.cc:123:45 错误:重载 'ClassA(ClassB&)' 的调用不明确

第二个,我明白了:

file2.hh:234:56 注意:没有已知的参数 1 从“ClassB”到“ClassA”的转换
file2.cc:123:45 错误:调用 'SomeOtherClass::someFunction(ClassB&)' 没有匹配的函数

当我注释掉 ClassB 中的类型转换运算符时,它将不再在 Solaris 上编译,并且所有错误消息都明显指出该运算符丢失。 Linux 上的错误消息没有改变。

根据这个:Conversion constructor vs. conversion operator: precedence,它应该同时查看运算符和构造函数,并且只有在它们同样有用时才抱怨歧义,对吧?
而且根据这个:conversion operator overloading ambiguity, compilers differ,编译器在转换时具有不同的行为可能是因为人们更努力地寻找可以完成转换的不同方式,但奇怪的是 gcc 甚至不会在之后寻找类型转换运算符找不到合适的构造函数。

为什么编译器在 Linux 上不使用 ClassB 的 ClassA 运算符将 ClassB 转换为 ClassA,而在 Solaris 上却这样做?

【问题讨论】:

  • 您可能需要澄清 methodOfClassA() 是否为 const。
  • methodOfClassA() 不是常量。我认为该行的错误来自从 ClassB 到 ClassA 的演员。
  • 我很想知道当被调用的方法 const 时会发生什么,因此它所操作的引用也可以是。它可能不会有什么不同,但如果没有别的,值得一看。
  • 它不会帮助任何人隐藏一半的错误消息。例如,我只能假设在第一种情况下,编译器还可能提供 ambiguous 替代方案......
  • 我会更详细地编辑;我认为消息中唯一重要的部分是它抱怨对构造函数的模棱两可的调用,而它显然应该使用类型转换运算符。

标签: c++ gcc casting compiler-errors


【解决方案1】:

转换会创建一个临时对象;临时对象不能绑定到非const 左值引用。 (这似乎不适用于您的“示例”代码,但错误消息也与示例不完全匹配,因此很难判断这是否是原因)。

有许多流行的编译器会出错并允许不正确的代码。

此外,对转换运算符执行可访问性检查。在您的示例中,B::operator ClassA() 是私有的。但是,这应该在错误消息中提及。

【讨论】:

  • -1:错误信息并不表示被调用的函数有引用,它表示实际参数是一个左值。为了确保,我在 Linux 上检查了 Sun C++,它不允许临时对象绑定到非 const 左值引用:“”test.cc”,第 4 行:错误:调用 g 时类型为 S& 的形式参数 1 (S&) 需要一个左值。”
  • Groan VS2010 还允许将临时变量作为左值参数传递。
  • @hvd:没错。但是,“示例”似乎不是真正的代码(名称不匹配),所以我将把它作为可能的解释。
  • B::operator ClassA() 应该是公开的,我的错误
  • @Cameron,您的意思是“VS2010 允许临时对象绑定到左值引用”吗?左值可以表示临时对象。
猜你喜欢
  • 2014-10-04
  • 2013-05-14
  • 1970-01-01
  • 2023-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-03
相关资源
最近更新 更多