我有以下代码:
typedef int AliasB;
typedef unsigned short AliasA;
class Alias
{
public:
explicit Alias(int someInt) { }
};
// (*) !! below breaks the conversion path via AliasA !!
//typedef Alias AliasA;
class C
{
public:
C() { }
};
class B
{
public:
B() { }
B(const AliasB& value) { }
operator AliasB() const
{
return -1000;
}
C combine(const B& someB)
{
return C();
}
};
class A
{
public:
A() { }
operator B() const
{
return B();
}
operator AliasA() const
{
return 1001;
// (*) !! below breaks the conversion path via AliasA !!
//return AliasA(1000);
}
A high()
{
return A();
}
A low()
{
return A();
}
C process()
{
return (static_cast<B>(low())).combine(static_cast<B>(high()));
// (**) !! the below compiles fine !!
//B theB = low();
//return theB.combine(high());
}
};
inline int someFunc(unsigned int someParam, const B& bParam)
{
return 1;
}
inline A createSomeA()
{
return A();
}
int main ()
{
A someA;
unsigned int counter = 200;
someFunc(counter, someA);
//someFunc(counter, static_cast<B>(createSomeA()));
someA.process();
return 0;
}
Clang报告以下错误:
clang_static_test.cpp:66:17: error: ambiguous conversion for static_cast from 'A' to 'B'
return (static_cast<B>(low())).combine(static_cast<B>(high()));
^~~~~~~~~~~~~~~~~~~~~
clang_static_test.cpp:21:7: note: candidate is the implicit copy constructor
class B
^
clang_static_test.cpp:25:5: note: candidate constructor
B(const AliasB& value) { }
^
clang_static_test.cpp:66:48: error: ambiguous conversion for static_cast from 'A' to 'B'
return (static_cast<B>(low())).combine(static_cast<B>(high()));
^~~~~~~~~~~~~~~~~~~~~~
clang_static_test.cpp:21:7: note: candidate is the implicit copy constructor
class B
^
clang_static_test.cpp:25:5: note: candidate constructor
B(const AliasB& value) { }
^
2 errors generated.
我无法弄清楚为什么编译器会产生错误,尽管我有 转换运算符已定义,我使用static_cast&lt;&gt;显式地在该特定位置进行转换。 该代码通过了GCC 4.5.2和Visual Studio 2008编译器的编译。 Clang版本是3.1,由我自己从Clang和LLVM的git存储库构建 几天前。
那么,Clang是否报告了实际错误?如果是的话,为什么这是一个错误 对我来说根本不明显(我不会问为什么其他编译器对此保持沉默)?
更新:示例代码现在是一个小的可编辑示例(抱歉从第一次不这样做)并复制我的实际情况。似乎AliasA的转换运算符是问题,因为如果它被删除,那么一切编译都很好。现在令人讨厌的是,对于上面的代码,我也从GCC得到了错误。
更新2 :我在示例中添加了一些代码,以更好地反映我的实际情况;唯一的区别是,对于上面的示例我也从GCC得到一个错误,而对于我的真实代码,我没有。
答案 0 :(得分:3)
static_cast
有两种方式将A转换为B:
使用A::operator B
并调用隐式复制构造函数B::B(const B& value)
来创建新的B
使用A::operator AliasA
,将结果转换为AliasB并调用B::B(const AliasB& value)
编译器不知道喜欢哪种方式。您可以通过编写以下内容来提示使用第二个选项:
someFunc(counter, static_cast<AliasA>(someA));
要使用第一个选项,您只需编写以下内容即可省略强制转换:
someFunc(counter, someA);
好吧,我不确定后者是否有明确的行为,但它至少与gcc和msvc有效。
答案 1 :(得分:3)
我已经向clang提交了一份有关此问题的错误报告。他们认为这不是一个错误。 C ++标准缺少此案例的规范,因此编译器将其报告为含糊不清。请参阅bug report。
我认为这种行为是违反直觉的。通过A ::运算符B()的第一条路径是完美匹配,而第二条路径涉及三种类型转换。唯一合乎逻辑的做法是将完美匹配看作是优越的。
如果在C ++标准中没有明确解析案例,编译器应该怎么做?
答案 2 :(得分:0)
我想我部分地想出了发生了什么,但我认为我不了解整个情况。所以编译器看到的转换路径如下所示:
/-------- A --------\
| |
| |
B AliasA(unsigned short)
| |
| |
copy ctor of B AliasB(int)
|
|
ctor B(const AliasB& value)
所以它是有道理的,编译器报告歧义是正确的(我喜欢clan'g错误和警告信息)。使其工作的一种方法是通过AliasA中断转换路径(请参阅问题示例代码中标有(*)的注释)。如果我打破有问题的表达式并且只依赖于隐式转换,而不是尝试显式static_cast&lt;&gt;任何事情(请参阅问题示例代码中标有(**)的注释)。但我并不完全掌握幕后发生的事情。我仍然不完全理解为什么它在(**)情况下表现不同,因为转换路径似乎是相同的,至少对于“theB.combine(high() )“部分。