而移植Windows代码到Linux,我遇到了以下错误消息GCC 4.2.3。 (是的,我知道,这是一个轻微的旧版本,但我不能轻松升级。)
main.cpp:16: error: call of overloaded ‘list(MyClass&)’ is ambiguous
/usr/include/c++/4.2/bits/stl_list.h:495: note: candidates are: std::list<_Tp, _Alloc>::list(const std::list<_Tp, _Alloc>&) [with _Tp = unsigned char, _Alloc = std::allocator<unsigned char>]
/usr/include/c++/4.2/bits/stl_list.h:484: note: std::list<_Tp, _Alloc>::list(size_t, const _Tp&, const _Alloc&) [with _Tp = unsigned char, _Alloc = std::allocator<unsigned char>]
我用下面的代码生成此错误。
#include <list>
class MyClass
{
public:
MyClass(){}
operator std::list<unsigned char>() const { std::list<unsigned char> a; return a; }
operator unsigned char() const { unsigned char a; return a; }
};
int main()
{
MyClass a;
std::list<unsigned char> b = (std::list<unsigned char>)a;
return 0;
}
有没有人经历过这样的错误? 更重要的是,如何解决呢? (这是可以完全避免过载,肯定的是,通过使用功能,如GetChar()
GetList()
等,但我想避免这种情况。)
(顺便说一句,去除“ operator unsigned char()
”中删除该错误)。
它正确编译,如果你删除的演员,我已经检查了正在执行的操作的std ::名单。
int main()
{
MyClass a;
std::list<unsigned char> b = a;
return 0;
}
或者,如果你将它转换为const引用。
int main()
{
MyClass a;
std::list<unsigned char> b = (const std::list<unsigned char>&)a;
return 0;
}
歧义来自铸表达的解释。
当选择了转换,编译器首先会考虑static_cast
风格的转换,并考虑如何解决初始化它看起来像这样:
std::list<unsigned_char> tmp( a );
这种构造是不明确的作为a
具有用户定义的转换到std::list<unsigned char>
和一个unsigned char
和std::list<unsigned char>
既具有构造这需要一个const std::list<unsigned char>&
以及一个构造这需要size_t
(到一个unsigned char
可以促进)。
当指定const std::list<unsigned_char>&
这个初始化被认为是:
const std::list<unsigned_char>& tmp( a );
在这种情况下,当用户定义的转换到std::list<unsigned_char>
被选择,新的参考可以直接绑定到转换的结果。 如果用户定义的转换到unsigned char
,其中选择类型的临时对象std::list<unsigned char>
将必须被创建,并且这使得该选项比前者选项较差的转换序列。
我已经简化你的榜样以下几点:
typedef unsigned int size_t;
template <typename T>
class List
{
public:
typedef size_t size_type;
List (List const &);
List (size_type i, T const & = T());
};
typedef List<unsigned char> UCList;
class MyClass
{
public:
operator UCList const () const;
operator unsigned char () const;
};
void foo ()
{
MyClass mc;
(UCList)mc;
}
第一点,是该标准定义了C样式转换应该使用更合适的C ++风格的类型转换,在这种情况下这是static_cast
。 所以,上面铸相当于:
static_cast<UCList> (mc);
的static_cast的定义说:
一个表达式e可以使用显式转换为一个类型T static_cast
形式static_cast<T>(e)
,如果声明"T t(e);"
是良好的,对一些发明临时变量t(8.5)
因此,对于中投的语义是一样的:
UCList tmp (mc);
从13.3.1.3我们得到了一组,我们可以使用候选构造的UCList
:
UCList (UCList const &) #1
UCList (size_type, T const & = T()); #2
接下来发生的事情是两个独立的重载解析步骤,每一个转换操作符。
转换为#1:随着目标类型UCList const &
,重载解析以下的转换运算符之间进行选择:“ operator UCList const ()
”和“ operator unsigned char ()
”。 使用unsigned char
将需要附加的用户的转换等等不是此过载步骤的可行功能。 因此重载解析成功,将使用operator UCList const ()
转换为#2:随着目标类型size_t
。 默认参数不采取重载决策的一部分。 过载分辨率转换运营商之间的再次选择:“ operator UCList const ()
”和“ operator unsigned char ()
”。 这一次,没有来自转化UCList
到unsigned int
,因此这不是一个可行的功能。 一个unsigned char
可以被晋升为size_t
,因此这一次重载成功,将采用“ operator UCList const ()
”。
但是,现在又回到在顶层有一些已经成功地从转换两个单独的和独立的重载解析步骤mc
来UCList
。 其结果是因此不明确的。
要说明的是最后一点,这个例子是正常的重载情况不同。 通常有一个1:参数和参数类型之间N的关系:
void foo (char);
void foo (short);
void foo (int);
void bar() {
int i;
foo (i);
}
这里有i=>char
, i=>short
和i=>int
。 这些被重载决议相比,和int
超载会被选中。
在上述情况下,我们有一个M:N的关系。 该标准列出的规则,选择为每个参数和所有的“N”的参数,但是这是它的尽头,它并没有规定我们应该如何使用不同的“m”参数之间决定。
希望这有一定的道理!
更新:
这两种这里初始化语法是:
UCList t1 (mc);
UCList t2 = mc;
“T1”是直接initialiation(13.3.1.3)和所有构造都包括在过载组。 这几乎等具有多于一个用户定义的转换。 有一组构造函数和一组转换操作符。 (即M:N)。
在“T2”的情况下,语法使用拷贝初始化(13.3.1.4)和规则不同:
下在8.5所规定的条件,如类类型的对象的副本初始化的一部分,用户定义的一个转换可以被调用来的初始化表达式转换为对象的类型被初始化。 重载分析被用于选择用户定义的转换将被调用
在这种情况下,只有一个输入, UCList
,所以只存在集转换操作符重载的考虑,即。 我们不考虑UCList的其他构造。