1

Consider following program it compiles and runs fine:

#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
}

But If I slightly change the main() function's code in like following:

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

Compiler give following error message (See live demo here)

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

Why this call is ambiguous? What is the reason behind that? It looks like there are so many overloaded operator= like one for char, one for char*, one for const char* etc. That's the above program puts compiler into ambiguity.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
Destructor
  • 14,123
  • 11
  • 61
  • 126

2 Answers2

5

Your problem is your template conversion operator.

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

Allows BB to be converted to anything. Because of that all of the overloads of std::string::operator= that take a different type can be considered. Since they are all valid there is no way to resolve the ambiguity and you get the error.

If you removed the template conversion then it will compile. The template conversion could also be marked as explicit and then you can use a static_cast to the type you want.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • 3
    If you make the templated conversion `explicit` it compiles as well. The `explicit` has the draw back that you would need a `static_cast` for it, but being explicit is probably a good idea with the conversion operators anyway. – Niall Oct 29 '15 at 14:52
  • 2
    @Niall Thanks for that. added it into the answer. – NathanOliver Oct 29 '15 at 14:59
2

You call operator =, but it would be the same if it were a regular function:

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

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

Since BB can be cast in either int or string, the compiler has no idea which f function to call.

The only reason why your first example works is because the copy constructor is called there, and it only takes const string& as an argument, so there's no multiple choices.

coyotte508
  • 9,175
  • 6
  • 44
  • 63