我在我的代码库中遇到了一个棘手的难题。我不知道为什么我的代码会生成此错误,但(例如)std :: string不会。
class String {
public:
String(const char*str);
friend String operator+ ( const String& lval, const char *rval );
friend String operator+ ( const char *lval, const String& rval );
String operator+ ( const String& rval );
};
这些实现很容易让你自己想象。
我的驱动程序包含以下内容:
String result, lval("left side "), rval("of string");
char lv[] = "right side ", rv[] = "of string";
result = lv + rval;
printf(result);
result = (lval + rv);
printf(result);
在gcc 4.1.2中生成以下错误:
driver.cpp:25: error: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second:
String.h:22: note: candidate 1: String operator+(const String&, const char*)
String.h:24: note: candidate 2: String String::operator+(const String&)
到目前为止这么好,对吗?遗憾的是,我的String(const char * str)构造函数非常方便使用隐式构造函数,使用explicit关键字来解决这个问题只会导致一堆不同的问题。
此外...... std :: string不必诉诸于此,我无法弄清楚原因。例如,在basic_string.h中,它们声明如下:
template<typename _CharT, typename _Traits, typename _Alloc>
basic_string<_CharT, _Traits, _Alloc>
operator+(const basic_string<_CharT, _Traits, _Alloc>& __lhs,
const basic_string<_CharT, _Traits, _Alloc>& __rhs)
template<typename _CharT, typename _Traits, typename _Alloc>
basic_string<_CharT,_Traits,_Alloc>
operator+(const _CharT* __lhs,
const basic_string<_CharT,_Traits,_Alloc>& __rhs);
等等。 basic_string构造函数未声明为显式。这怎么不会导致我得到同样的错误,我怎样才能实现相同的行为?
答案 0 :(得分:9)
模糊性的原因是,只有当其参数的 none 比另一个的参数更差时,一个候选函数优于另一个候选函数。考虑你的两个功能:
friend String operator+(const String&, const char*); // (a)
String operator+(const String&); // (b)
您使用operator+
和String
致电const char*
。
类型const char*
的第二个参数明显与(a)比(b)更好。它与(a)完全匹配,但(b)需要用户定义的转换。
因此,为了存在歧义,第一个参数必须与(b)相比(a)更好。
String
调用左侧的operator+
不是常量。因此,它匹配(b),这是一个非const成员函数,优于(a),它取const String&
。
因此,以下任何解决方案都可以消除歧义:
operator+
更改为const成员函数operator+
更改为String&
而不是const String&
operator+
显然,第一个also suggested by UncleBens是最好的方式。
答案 1 :(得分:5)
在这种情况下,仅在operator+
:
String operator+(const String& lval, const String& rval);
由于您提供了使用char*
的构造函数,因此在调用String
期间可以从char*
构建operator+
。例如:
String hello = "Hello, ";
const char* world = "world!";
String helloWorld = hello + world;
将使用String
char*
的内容构建临时world
(因为您的构造函数不明确),然后将两个String
对象传递给operator+
。
答案 2 :(得分:3)
如果您声明成员+ const ,错误就会消失。
class String {
public:
String(const char*str);
friend String operator+ ( const String& lval, const char *rval );
friend String operator+ ( const char *lval, const String& rval );
String operator+ ( const String& rval ) const; //<-- here
};
不确定是什么原因。如果可能的话,它可能更喜欢将绑定参数绑定到const引用,因此第一次重载更好地匹配左侧值,第三次重载更好地匹配右侧值。
Better explanation.(必须误解一下这个问题。)
printf(result);
不要告诉我你的String已隐式转换为const char*
......这是邪恶的。
答案 3 :(得分:2)
模板和非模板函数遵循不同的规则。在实际参数类型上选择模板函数,而不应用任何转换。对于非模板(即您的代码),可以应用隐式转换。因此,basic_string中的模板化内容不含糊,但你的是。
答案 4 :(得分:1)
您已经证明basic_string
的{{1}}实现与您的班级operator+
中的第二个和第三个运算符相对应。 String
是否还有与您的第一个运算符[basic_string
]对应的运算符?
如果删除此运算符会怎样?