C ++加法过载模糊

时间:2010-04-10 14:08:35

标签: c++ gcc operator-overloading stdstring

我在我的代码库中遇到了一个棘手的难题。我不知道为什么我的代码会生成此错误,但(例如)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构造函数未声明为显式。这怎么不会导致我得到同样的错误,我怎样才能实现相同的行为?

5 个答案:

答案 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&
  • 使用左侧的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]对应的运算符?

如果删除此运算符会怎样?