2015-10-29 7 views
1

Рассмотрим следующую программу она компилируется и работает нормально:Почему эта операция присваивания приводит к неоднозначному вызову функции?

#include <iostream> 
#include <string> 
using std::string; 
struct BB 
{ 
// generic cast 
template<typename T> 
operator T() const 
{ 
    std::cout<<"Generic cast\n"; 
    return 0; 
} 
// string cast 
operator string() const 
{ 
    std::cout<<"string cast\n"; 
    return string("hello"); 
} 
}; 
int main() 
{ 
    BB b; 
    string s = b; // copy constructor 
} 

Но если я немного изменить код в main() функция в, как следующее:

int main() 
{ 
    BB b; 
    string s; 
    s = b; 
} 

Компилятор дают следующее сообщение об ошибке (See live demo here)

[Error] ambiguous overload for 'operator=' (operand types are 'std::string {aka std::basic_string<char>}' and 'BB') 

Почему этот вызов неоднозначен? В чем причина этого? Похоже, что столько перегруженных operator=, как один для char, один для char*, один для const char* и т. Д. Это вышеперечисленная программа ставит компилятор в двусмысленность.

+4

В первом случае это не оператор присваивания, а копия ctor. Однако я считаю, что во втором случае существует двусмысленность между оператором литья шаблонов и строкой. – MaMazav

+0

@MaMazav: да, вы правы. Но мой вопрос касается второго случая, когда = оператор входит в картину. – Destructor

+2

На странице liveemo в сообщении об ошибке также перечислены все кандидаты, рассмотренные компилятором для решения задания во втором случае –

ответ

5

Ваша проблема - ваш оператор преобразования шаблонов.

template<typename T> 
operator T() const 
{ 
    std::cout << "Generic cast\n"; 
    return 0; 
} 

Позволяет BB быть преобразовано в что угодно. Из-за этого могут учитываться все перегрузки std::string::operator=, которые принимают разные типы. Поскольку все они действительны, невозможно устранить двусмысленность, и вы получите ошибку.

Если вы удалили преобразование шаблона, он скомпилируется. Преобразование шаблона также можно пометить как explicit, а затем вы можете использовать static_cast по типу, который вы хотите.

+3

Если вы делаете шаблонное преобразование «явным», оно также компилируется. «Явный» имеет обратную сторону, для которой вам понадобится «static_cast», но быть явным - это, вероятно, хорошая идея с операторами преобразования. – Niall

+2

@Niall Спасибо за это. добавили его в ответ. – NathanOliver

2

Вы называете operator =, но это было бы то же самое, если бы это была регулярная функция:

void f(int x); 
void f(const string &y); 

int main() { 
    BB b; 
    f(b); 
    return 0; 
} 

С BB может быть отлит в любом int или string, компилятор не имеет понятия, которые f функция для вызова.

Единственная причина, по которой ваш первый пример работает, заключается в том, что здесь вызывается конструктор копирования, и в качестве аргумента он принимает только const string&, поэтому выбора не существует.