KeyBored
KeyBored

Reputation: 621

Why calling the "<<" operator as a function causes "ambiguous call" compiler error?

Why the first code snippet works fine, but the second causes an ambiguous call error ? Why cannot the compiler resolve the function overload in the second case ?

Snippet 1:

int main() {
    int x = 1234;
    std::cout << x;
}

Snippet 2:

int main() {
    int x = 1234;
    operator<<(std::cout, x);
}

The compiler error when compiling the snippet 2:

more than one instance of "operator<<" matches the argument list

std::operator <<': ambiguous call to overloaded function

Upvotes: 2

Views: 173

Answers (4)

BoBTFish
BoBTFish

Reputation: 19757

You are trying to call a member function (of std::cout) as if it were a free function: http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt

The ambiguity probably comes from multple matches that all involve some sort of conversions, none of which is preferable. The compiler error probably gives you some horrendous impossible-to-read list of possible matches, all of which seem irrelevant?


For operators, call them as operators, not as functions! There are good reasons to define operators as members, and good reasons to define them as free functions. You shouldn't need to care which is used in any particular case.

If I want to create my own type that supports +, I may have good technical reasons to choose one approach over the other, and even change my mind in a future version of the library. Should you care which I choose?


Note that operator<< is a member function for built-in types (i.e. the various flavours of ints), but is a non-member function for other types, for example char const* or std::string.

Upvotes: 4

Li Chen
Li Chen

Reputation: 5260

From here:

template< class Traits >
basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,
                                        char ch );

template< class Traits >
basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,
                                        signed char ch );

The call will be ambiguous if overload resolution cannot select a match to the call that is uniquely better than such undifferentiable functions. For x(int), both char version and signed char version are fit, so it will be ambiguous. One more example:

#include <iostream>
void foo(char a)
{

}
void foo(signed char b)
{

}
int main() {
    foo(1);
}

prog.cc: In function 'int main()': prog.cc:11:10: error: call of overloaded 'foo(int)' is ambiguous foo(1);


But this code works fine operator<<(std::cout, "hello");

Because

template< class Traits > basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& const char* s );

is the only choice for operator<<(std::cout, "hello");. One more example:

const char* z = "char*";  // OK 
const signed char* x = "signed char*";  // invalid conversion from ‘const char*’ to ‘const signed char*’ 
const unsigned char y = "unsigned char*"; // invalid conversion from ‘const char*’ to ‘unsigned char’ 

Upvotes: 0

nullqube
nullqube

Reputation: 2999

The operator is a nonstatic member function, so you could use from : how to call an operator as function in C++

#include <iostream>

int main() {
    int x = 1234;
    std::cout.operator<<(x);
}

Upvotes: 1

Some programmer dude
Some programmer dude

Reputation: 409136

Because there is no global (or non-member) operator<< overloaded function for integers. It's a member of the output stream:

std::cout.operator<<(x);

A good compiler should have shown you the possible alternatives for an ambiguous call, which should have told you this.

Upvotes: 4

Related Questions