C++加法过载歧义
我的代码库中遇到了一个令人烦恼的难题。我不太清楚为什么我的代码会生成此错误,但(例如) 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) 构造函数作为隐式构造函数非常方便,使用显式关键字来解决这个问题只会导致一堆不同的问题。
此外... 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 构造函数未显式声明。这如何不会导致我遇到的相同错误,以及如何实现相同的行为?
I am coming up against a vexing conundrum in my code base. I can't quite tell why my code generates this error, but (for example) std::string does not.
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 );
};
The implementation of these is easy enough to imagine on your own.
My driver program contains the following:
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);
Which generates the following error in 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&)
So far so good, right? Sadly, my String(const char *str) constructor is so handy to have as an implicit constructor, that using the explicit keyword to solve this would just cause a different pile of problems.
Moreover... std::string doesn't have to resort to this, and I can't figure out why. For example, in basic_string.h, they are declared as follows:
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);
and so on. The basic_string constructor is not declared explicit. How does this not cause the same error I'm getting, and how can I achieve the same behavior??
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
造成歧义的原因是,只有当一个候选函数的参数没有一个比另一个候选函数的参数匹配更差时,该候选函数才比另一个候选函数更好。考虑您的两个函数:
您正在使用
String
和const char*
调用operator+
。第二个参数的类型为 const char*,显然与 (a) 匹配得比 (b) 更好。它与 (a) 完全匹配,但 (b) 需要用户定义的转换。
因此,为了避免歧义,第一个参数必须比 (a) 更好地匹配 (b)。
对
operator+
调用左侧的String
不是 const。因此,它与作为非常量成员函数的 (b) 匹配,比采用const String&
的 (a) 更好。因此,以下任何解决方案都可以消除歧义:
operator+
更改为 const 成员函数operator+
更改为采用String&
而不是const String&
operator+
显然,第一个,UncleBens 也建议,是最好的方法。
The reason for the ambiguity is that one candidate function is better than another candidate function only if none of its parameters are a worse match than the parameters of the other. Consider your two functions:
You are calling
operator+
with aString
and aconst char*
.The second argument, of type
const char*
, clearly matches (a) better than (b). It is an exact match for (a), but a user-defined conversion is required for (b).Therefore, in order for there to be an ambiguity, the first argument must match (b) better than (a).
The
String
on the left-hand side of the call tooperator+
is not const. Therefore, it matches (b), which is a non-const member function, better than (a), which takes aconst String&
.Therefore, any of the following solutions would remove the ambiguity:
operator+
to be a const member functionoperator+
to take aString&
instead of aconst String&
operator+
with a const String on the left hand sideObviously, the first, also suggested by UncleBens, is the best way to go.
在这种情况下,只需在
operator+
上定义就足够了:因为您提供了一个采用
char*
的构造函数,所以可以从调用operator+
期间的char*
。例如:将使用
char*
world
的内容构造一个临时String
(因为您的构造函数不显式),然后两个String
对象将被传递给operator+
。It is sufficient in this case just to define on
operator+
:Because you provide a constructor taking a
char*
, aString
can be constructed from achar*
during the call tooperator+
. For example:A temporary
String
will be constructed with the contents of thechar*
world
(because your constructor is not explicit), then the twoString
objects will be passed tooperator+
.如果您按照应有的方式声明成员 + const ,错误就会消失。
但不确定原因是什么。如果可能的话,它可能更喜欢绑定参数而不是 const 引用,因此第一个重载更适合左侧值,第三个重载更适合右侧值。更好的解释。(一定有点误读了问题。)
不要告诉我你的字符串有隐式转换为
const char*
...这很邪恶。The error goes away if you declare the member + const as it should be.
Not sure what's the reason, though. Perhaps it prefers binding arguments to const reference if possible, so the first overload is a better match for the left-hand value and the third overload has a better match for the right-hand value.Better explanation. (Must have misread the problem a bit.)
Don't tell me your String has implicit conversion to
const char*
... That's evil.模板函数和非模板函数遵循不同的规则。模板函数是根据实际参数类型选择的,不应用任何转换。在非模板(即您的代码)的情况下,可以应用隐式转换。因此 basic_string 中的模板化内容并不含糊,但你的却是。
Template and non-template functions follow different rules. The template functions are selected on the actual parameter types, without any conversions being applied. In the case of the non-template (i.e. your code) an implicit conversion can be applied. Thus the templated stuff in basic_string is not ambiguous, but yours is.
您已经展示了
basic_string
具有与String
类中的第二个和第三个运算符相对应的operator+
实现。basic_string
是否也有一个与您的第一个运算符 [friend String operator+ ( const String& lval, const char *rval );
] 相对应的运算符?如果删除这个运算符会发生什么?
You've shown that
basic_string
has implementations ofoperator+
corresponding to the second and third operators in your classString
. Doesbasic_string
also have an operator corresponding to your first operator [friend String operator+ ( const String& lval, const char *rval );
]?What happens if you remove this operator?