Неоднозначный вызов конструктора

Рейтинг: 2Ответов: 2Опубликовано: 16.04.2015

Уважаемые друзья, у меня наблюдается следующая проблема. Есть такой код:

 class Verylong
 {
 public:
    Verylong (long x = 0) { enter(x);}
    Verylong (const Verylong& vrl) : _sign(vrl._sign), lnum(vrl.lnum) {/*empty*/}
    explicit Verylong (const std::string& str) { enter(str);}    
    explicit Verylong (const char* ch) { std::string str(ch); enter(str);}
    // ...
};

При вызове

return Verylong(0);

я получаю следующую ошибку:

D:\c++\verylong.h: In member function 'my::Verylong my::Verylong::operator*(const my::Verylong&) const': D:\c++\verylong.h:461:30: error: call of overloaded 'Verylong(int)' is ambiguous return Verylong(0); ^ D:\c++\verylong.h:461:30: note: candidates are:

D:\c++\verylong.h:58:22: note: my::Verylong::Verylong(const char*) explicit Verylong (const char* ch) { std::string str(ch); enter(str);}

^ D:\c++\verylong.h:56:22: note: my::Verylong::Verylong(const string&) explicit Verylong (const std::string& str) { enter(str);} ^

D:\c++\verylong.h:54:13: note: my::Verylong::Verylong(const my::Verylong&) Verylong (const Verylong& vrl) : _sign(vrl._sign), lnum(vrl.lnum) {/empty/} ^

D:\c++\verylong.h:52:13: note: my::Verylong::Verylong(long int) Verylong (long x = 0) { enter(x);}

В чём дело? Откуда берётся неоднозначность и как её правильно устранить?

Ответы

▲ 6

Исправить ошибку выше довольно просто:

return Verylong(0L);  // Здесь больше нет ошибки

Проблема в том, что используя Verylong(0) Вы получаете неоднозначность, т.к. 0 имеет тип int, а у Вас нет конструктора, принимающего тип int. Зато есть 3 конструктора, которые могли бы поучаствовать в перегрузке:

  • Verylong(long x = 0) - требует одной конвертации из int в long
  • Verylong(const char* ch) - требует одной конвертации из 0 в const char*
  • Verylong(const std::string& str) - требует 2 конвертации, сначала в const char*, потом создаётся временный объект std::string. В терминах стандарта сначала происходит standard conversion(0-> const char*), затем user-defined conversion(std::string(const char*) конструктор), затем standard conversion(identity). Подробнее в стандарте C++(13.3.3.1.2):

A user-defined conversion sequence consists of an initial standard conversion sequence followed by a userdefined conversion (12.3) followed by a second standard conversion sequence. If the user-defined conversion is specified by a constructor (12.3.1), the initial standard conversion sequence converts the source type to the type required by the argument of the constructor. If the user-defined conversion is specified by a conversion function (12.3.2), the initial standard conversion sequence converts the source type to the implicit object parameter of the conversion function.

Так вот, с точки зрения компилятора первый и второй случаи абсолютно равнозначны и, следоваетльно,- ошибка. Если же Вы явно указываете, что константа типа long, то конструктор Verylong(long x = 0) более не требует конвертации и однозначно выигрывает "гонку" перегрузок.

▲ 1
Verylong (int x = 0) { enter(x);}