confusion about C++ name lookup - c++

According to my knowledge, the name in a nested scope will hide the same name in the enclosing scope, just like what shows below:
namespace ttt {
class A {};
void test(const A&, int)
{
cout << "ttt::test()" << endl;
}
}
void test(const ttt::A&, int)
{
cout << "global::test()" << endl;
}
int main()
{
void test(const ttt::A&, int);
ttt::A a;
test(a, 1);
}
the declaration of void test(const ttt::A&, int); in the main function hides the same name which is in the namespace ttt, so the console prints global::test()(Tested in Visual Studio 2019)
However, when I try the code below:
std::ostream& operator<< (std::ostream& os, const string& str)
{
os << "global::operator" << endl;
return os;
}
int main()
{
std::ostream& operator<< (std::ostream & os, const string & str);
string a = "STD's operator";
cout << a << "STD's operator" << endl;
}
I try to overload the << operator which is a template defined in STL with my own version of <<. According to the first example, the declaration of operator<< in main should hide the STL defined version of <<, then the desired output should be
global::operator
global::operator
global::operator
or a compile error, since I don't know whether endl can be converted to string.
however, the result of the program is:
global::operator
STD's operator
So the second and the last << in the statement cout << a << "STD's operator" << endl; invokes the STL's <<, not the overloaded one define by me. Shouldn't the << already be hidden by the declaration std::ostream& operator<< (std::ostream & os, const string & str); in main ?
Someone may say "STD's operator" is const char*, so that the Argument Dependent Lookup(ADL) adds a better candidate which is std::ostream& operator<< (std::ostream&, const char*) from std namespace. If this is true, then how to explain the first example. The ADL procedure in the first example may add ttt::test(const A&, int) into overloading candidate and that would cause ambiguity in the first example, but that didn't happen, the ttt::test(const A&, int) just been hidden.
Page 798 of "C++ primer 5th" says that "When we pass an object of a class type to a function, the compiler searches the namespace in which the argument’s class is defined in addition to the normal scope lookup". I think my confusion is about the accurate meaning of in addition to.
If it means that the class's namespace has the same precedence of the scope where the function is called, then the first example should cause ambiguity.
If it means that the class's namespace has lower precedence, then all the << in the main function in the second example should be hidden by the version defined by me.
If it means that the class's namespace has higher precedence, then the first example should print "ttt::test()".
So what happened?

ADL is not performed if one of the candidate functions is declared at block scope, like your block scope function declarations. (When ADL is performed, it indeed has no special preferential treatment when picking the most viable candidate)
So your first example, void test(const ttt::A&, int); (which is a block scope declaration for ::test), means that ttt::test is no longer a candidate, and the global ::test is called (removing the block scope declaration makes it ambiguous)
I believe that you are correct here and the second example should call your global operator after constructing a std::string.
Compilers seem to agree that std::cout << a << "STD's operator" << std::endl compiles to the equivalent of std::operator<<(::operator<<(std::cout, a), "STD's operator").operator<<(std::endl). The << std::endl is fine since it's found by member lookup instead of ADL. The problem is that ADL is still used to find std::operator<<(std::ostream&, const char*)
Reading directly from the C++11 standard on what should happen:
"Operators in expressions" [over.match.oper]p2:
If either operand has a type that is a class or an enumeration, a user-defined operator function might be declared that implements this operator [...]. In this case, overload resolution is used to determine which operator function or built-in operator is to be invoked to implement the operator. Therefore, the operator notation is first transformed to the equivalent function-call notation as summarized in Table 11 (where # denotes one of the operators covered in the specified subclasses)
Both operands are of class types, so user-defined operator functions are considered as expected. The relevant subclause of table 11 is 13.5.2, with the expression a#b, which is (a).operator#(b) as a member function and operator#(a, b) as a non-member function.
[over.match.oper]p3
[...] for a binary operator # with a left operand of type cv1 T1 and a right operand of type cv2 T2, three sets of candidate functions, designated member candidates, non-member candidates and built-in candidates, are constructed as follows:
[...]
The set of non-member candidates is the result of the unqualified lookup of operator# in the context of the expression according to the usual lookup in unqualified function calls (3.4.2) except that all member functions are ignored.
Where §3.4.2 is [basic.lookup.arg] "Argument-dependent name lookup".
[basic.lookup.arg]p3 says:
Let X be the lookup set produced by unqualified lookup (3.4.1) and let Y be the lookup set produced by argument dependent lookup (defined as follows). If X contains
a declaration of a class member, or
a block-scope declaration that is not a using-declaration, or
a declaration that is neither a function or a function template
then Y is empty. [...] The set of declarations found by the lookup of the name is the union of X and Y.
Looking only at std::cout << "STD's operator" for simplicity, the name looked up is operator<<. The unqualified lookup finds the block scope declaration for std::ostream& operator<< (std::ostream & os, const string & str); only (and all other declarations are hidden). But since the function declaration in a block scope was found, ADL shouldn't happen and there are no further non-member candidates.
Thus the set of candidate functions is only the global ::operator<<(std::ostream & os, const string &) and the member operator<< in std::ostream and its base classes, of which the global function is the most viable.
Compilers seem to ignore this rule when looking up operators, always performing ADL even if there is a block scope declaration. Writing operator<<(std::cout, "STD's operator") does it correctly and outputs global::operator.

Only in addition to #Artyer's answer.
In practice, you shouldn't ever provide a different definition of std:: functions in a different namespace because the call may accidentally go into a std:: version, with no warning or error.
The robust solution is to name your functions differently or wrap you arguments in a different class object, so that you never accidentally call a std:: function when you don't intend to.
For example, if you want a version of std::isnan that works correctly with -ffast-math, call it isnan2, not isnan which might resolve into std::isnan.
A part of being a good software engineer is preventing potential problems for yourself in the future. And avoiding name clashes with std:: functions which may be found via ADL is robust engineering - a philosophy or way of thinking about engineering that makes accidental semantic changes of existing correctly working code impossible.
In your example, there is no need or justification for creating another version of std::operator<< in another namespace. But there are undesirable problems which arise from from such a decision. In other words, the reward is 0, but the risk is infinite.

Related

`std::cout << FooStuff::Foo();` chooses completely unrelated overload instead of exactly matching one

I have this code:
#include <iostream>
namespace FooStuff
{
struct Foo { };
}
decltype(std::cout)& operator << (decltype(std::cout)& left, const FooStuff::Foo& right)
{
return left;
}
void test1()
{
// This works fine
std::cout << FooStuff::Foo();
}
As far as I can tell, this is the best operator << that one could possibly write down to match the call in test1, and it works as you would expect.
Now add this code below the code above:
namespace BarStuff
{
struct Bar { };
// Danger zone
void test2()
{
// This works too, for now
std::cout << FooStuff::Foo();
}
}
The call in test2 works too, as you would expect.
But if I insert the following operator right below the "Danger zone" comment, everything breaks:
Bar operator << (Bar left, Bar right)
{
return left;
}
Now the call in test2 won't compile because the compiler chooses the completely inappropriate overload that takes a bunch of Bars, even though the operator from the first snippet should be a perfect match:
main.cpp:33: error: invalid operands to binary expression ('std::ostream' (aka 'basic_ostream<char>') and 'FooStuff::Foo')
(A ton of unrelated overloads omitted for brevity)
main.cpp:25: candidate function not viable: no known conversion from 'std::ostream' (aka 'basic_ostream<char>') to 'BarStuff::Bar' for 1st argument
What the poop is going on? Why does the compiler choose that overload instead of the one I want it to choose?
And why does the error disappear, if Foo is moved outside FooStuff?
When you write std::cout << FooStuff::Foo(); name lookup is done to determine the candidates for << to use in overload resolution.
For overload resolution of operators there are two parts to this lookup: unqualified name lookup of operator<< and argument-dependent lookup of operator<<.
For unqualified name lookup, as is always the case, lookup traverses from inner to outer scope and stops as soon as a match is found. So if you put an overload at // Danger zone, the one outside BarStuff will be hidden.
For argument-dependent name lookup, all overloads in the class types of the operands and their immediately enclosing namespace will be considered. In your case that means that overloads inside struct Foo and namespace FooStuff will be found as well, no matter where the std::cout << FooStuff::Foo(); is placed.
For the above reasons, operator overloads should be placed in the namespace containing the class for which they overload the operator. This assures that the overload is always found via argument-dependent lookup.

Does member function like operator<< , operator* need ADL to work?

I have a code snippet (Hypothetically):
#include <iostream>
struct Pirate {
void song_name() {
std::cout << "Bink's Sake\n";
}
Pirate& operator*(Pirate const& other) {
// do something
return *this;
}
};
int main() {
Pirate p1{} p2{};
p1.song_name(); // does this use qualified or unqualifed name lookup?
p1 * p2;
std::cout << 5;
std::cout << 'a';
}
Does p1 * p2 use qualified name lookup or unqualified name lookup or ADL?
std::cout << 5 transforms into std::cout.operator<<(5);
std::cout << 'a' transforms into std::operator<<(std::cout, 'a');
Does member functions require ADL to work?
Does the above two statments use qualified or unqualifed name lookup or ADL?
Thanks
The operators lookup non-static member functions like
std::cout.operator<<(5);
but also non-member functions via unqualified lookup and ADL if they have a non-member variant. All of these together form the overload set.
For this to work correctly non-member variants should be found via ADL, i.e. placed inside the namespace of the class for which they are overloading the operator. E.g. for overloading operator<< for your own classes you cannot use a member version, because the first argument is probably supposed to be anything derived from std::ostream. Then ADL on the non-member variant is the only way to make it work everywhere.
A name is a qualified name if the scope to which it belongs is explicitly denoted using a scope-resolution operator (::) or a member access operator (. or ->).
Case 1
Thus, when you wrote:
p1.song_name(); //here p1.song_name is a qualified name
In the above statement, p1.song_name is a qualified name and so here qualified lookup takes place.
Case 2
Next, when your wrote:
p1 * p2;
The above statement is equivalent to:
p1.operator*(p2);
Since your class Pirate have an overloaded member function operator*, the above statement will use that member function. The above statement uses qualified lookup as well because we have used the member access operator ..
Case 3
Here we have the statement:
std::cout << 5;
The above statement is equivalent to:
std::cout.operator<<(5);
which uses qualified lookup since it has member access operator .
Case 4
Here we look at the statement:
operator<<(std::cout, 'a');
Here the char overload from operator<< for ofstream is used. This uses ADL because in this case the first parameter has a class type. So the compiler will also look in the namespace in which cout is defined. Thus, for this call, the compiler also looks in the std namespace and finds the char overload.

Difference between `cout << x` and `cout.operator<<(x)` and `operator(std::cout, x)`?

This is related to the difference-between-cout-x-and-cout-operator-x question, but still a little different...
#include <iostream>
int main(){
std::cout << "hello" << std::endl;
std::cout.operator<<("hello2");
std::cout.operator<<(std::endl);
operator<<(std::cout, "hello3");
// operator<<(std::cout, std::endl);
return 0;
}
Q1: Why does std::cout.operator<<("hello2"); work?
From other answers on SO I would expect the compiler to complain since operator<< is meant to be a free function and not a member of cout. On my system, however, it prints "0x10d54df31". And, stranger yet, the following line correctly correctly executes std::endl.
Q2: Why does operator<<(std::cout, std::endl); not work?
I know that std::endl is a function, but it seems strange (to me) that the hello3 output works whilst the `std::endl' doesn't. Instead the compiler throws an error:
main.cpp:10:4: error: no matching function for call to 'operator<<'
operator<<(std::cout, std::endl);
Q3: How can the first std::cout << "hello1" << std::endl; be written in operator<<(...) form?
If the first two questions have been answered, then this has probably already covered. It's the point of this learning exercise, so seems sensible to ask it explicitly.
Operators can be implemented in different ways, in particular an operator<< for which the left hand side is your type can be implemented as either a free function or as a member function of that left hand side type.
While you must implement ostream& operator<<(ostream&, MyType const&) as a free function (since MyType is not the left hand side), the library implementation can choose* to implement operator<< for some fundamental types insde the std::ostream type (which is really a particular instantiation of a template, I am trying to ignore the details).
Edit: After checking with the standard this is incorrect:
This is what you are noticing in the code, the overload that takes a const char* is implemented as a member of ostream (basic_ostream<char,char_traits<char>).
The overloads taking manipulators are implemented as member functions (Q2), and there is an implicit conversion from const char* to const void* that will be picked if you use the syntax for explicitly calling a member operator (Q1). For Q3, the answer would be:
operator<<(std::cout, "Hello").operator<<(std::endl);
* The implementation is actually not free to choose, since the standard mandates the signatures.
Some overloads of operator<< are class members, others are not.
In C++03 this created some baffling call scenarios since a reference to non-const (argument of the not-member) can't be bound to an rvalue, but in C++11 at least one such has been fixed by introducing an rvalue reference argument overload.
So, which calls compile or not depends more in general also on the C++ standards version, C++03 or C++11.
There is a bunch of member output operators defined in std::ostream. In retrospect that was probably an error but when IOStreams were first created I think it was actually necessary. These member operators include the overloads taking function pointers which means you'll need to use member notation for those. The operators using C-strings are non-member overloads, i.e., you need to use the non-member function call notation to get the C-string overload. When you call the member operator with a char const* the char const* will be converted to void const* for which there is a member output operator.
Your questions can be broken down to member functions an non-member functions.
Having 13.5.2 Binary operators
A binary operator shall be implemented
either by a non-static member function (9.3) with one parameter or by
a non-member function with two parameters. Thus, for any binary
operator #, x#y can be interpreted as either x.operator#(y) or
operator#(x,y). If both forms of the operator function have been
declared, the rules in 13.3.1.2 determine which, if any,
interpretation is used.
Omitting a quote of 13.3.1.2 the member function (operator) is preferred.
The line 'std::cout << "hello" << std::endl;' involves non member functions. Each 'std::cout.operator' is an explicit member function call.
Q1 is the member operator<<(const void*)
Q2 there is no member taking a function
Q3 It is not possible

Why I have to write std::cout and not also std::<<

Why do I have to write std::cout and not also std::<< in a line of code like this:
#include <iostream>
int main() {
std::cout << "Hello, world!";
return 0;
}
cout comes from std library, and isn't << usually used to do bits shifting? So, why don't I have to write the scope operator :: also before <<, since it is used also with another meaning? How the compiler knows that after std::cout, << means another thing?
First, the compiler will look at the types to the left and right of <<. std::cout is of type std::ostream, the string literal is of type array of 15 const char. As the left is of class type, it will search for a function named operator<<. The question is, where will it look?
The lookup for this name operator<< is a so-called unqualified lookup, because the function name isn't qualified like std::operator<<. Unqualified lookup for function names invokes argument-dependent lookup. The argument-dependent lookup will search in the classes and namespaces associated with the argument types.
When you include <iostream>, a free function of the signature
template<typename traits>
std::basic_ostream<char, traits>& operator<<(std::basic_ostream<char, traits>&,
const char*);
has been declared in namespace std. This namespace is associated with the type of std::cout, therefore this function will be found.
std::ostream is just a typedef for std::basic_ostream<char, std::char_traits<char>>, and the array of 15 const char can be converted implicitly to a char const* (pointing to the first element of the array). Therefore, this function can be called with the two argument types.
There are other overloads of operator<<, but the function I mentioned above is the best match for the argument types and the one selected in this case.
A simple example of argument-dependent lookup:
namespace my_namespace
{
struct X {};
void find_me(X) {}
}
int main()
{
my_namespace::X x;
find_me(x); // finds my_namespace::find_me because of the argument type
}
N.B. As this function is a operator, the actual lookup is a bit more complex. It is looked up via qualified lookup in the scope of the first argument (if that's of class type), i.e. as a member function. Additionally, unqualified lookup is performed, but ignoring all member functions. The result is slightly different, because unqualified lookup is actually like a two-step procedure, where argument-dependent lookup is the second step. If the first step finds a member function, the second step is not performed, i.e. argument-dependent lookup is not used.
Compare:
namespace my_namespace
{
struct X
{
void find_me(X, int) {}
void search();
};
void find_me(X, double) {}
void X::search() {
find_me(*this, 2.5); // only finds X::find_me(int)
// pure unqualified lookup (1st step) finds the member function
// argument-dependent lookup is not performed
}
}
to:
namespace my_namespace
{
struct X
{
void operator<<(int) {}
void search();
};
void operator<<(X, double) {}
void X::search() {
*this << 2.5; // find both because both steps are always performed
// and overload resolution selects the free function
}
}
In std::cout << "Hello, world!"; //calls std:::operator <<
This is achieved with Argument-dependent name lookup (ADL, aka Koenig Lookup)
Although we have only one std qualifier but there are two things that comes up from std namespace
cout
<<
Without ADL, (Koenig Lookup)
std::cout std:: << "Hello World" ;//this won't compile
In order to compile it, we need to use it more uglier form
std::operator<<(std::cout, "Hello, world!");
So to avoid such ugly syntax we must appreciate Koenig Lookup :)
The compiler sees that the arguments to << are an std::ostream object and a string, and so is able to locate the proper operator<< definition based on this.
You can sort of think of the argument types of an operator (or really, any function) as part of its name.

C++ overloading

The following code is giving me a compilation error. Can anyone please tell me why?
class mytype {
public:
int value;
mytype(int a) {
value = a;
}
friend ostream& operator<<(ostream& stream, const mytype& a) {
stream << a.value;//works
return stream;
}
friend ostringstream& operator<<(ostringstream& stream, const mytype& a) {
stream << (a.value);//compilation error
return stream;
}
};
Error:
error C2027: use of undefined type
'std::basic_ostringstream<_Elem,_Traits,_Alloc>'
Upon fixing that:
error C2666: 'operator <<' : 18 overloads have similar conversions
Final fix:
Declare constructor as explicit. Works on MSVC then.
I wonder why.
error C2027: use of undefined type 'std::basic_ostringstream<_Elem,_Traits,_Alloc>'
You need #include <sstream> to get the [i/o]stringstream classes.
About the other errors
The problem with an overload of the form
ostringstream& operator<<(ostringstream& stream, const mytype& a)
is that it matches an ostringstream exactly. Why is it a bad thing to have a more exact overload? From the standard, §13.3.3/1-2:
a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2) …
If there is exactly one viable function that is a better function than all other viable functions, then it is the
one selected by overload resolution; otherwise the call is ill-formed
Therefore if operator<<( ostream &, int ) and operator<<( ostringstream &, mytype const & ) are both candidates for stream << value, the former matches int exactly with no conversion but the latter matches ostringstream exactly. Therefore neither can be "not worse" for all arguments, and neither candidate may be chosen.
But the code is valid because of a loophole. Your overload is not a candidate at all, except when you actually use your type in the function call. When you declare/define a friend inside a class block, it does not introduce it to any namespace scope; it merely associates it with the class scope, which allows it to be found if that class type describes one of the arguments being passed.
The standard has this to say about friend declarations, although it's in another section (14.6.5):
Friend declarations do not introduce new names into any scope…
So, MSVC tried to be nice and proactively introduced your friend to its enclosing namespace. Strike against MSVC.
However, when I attempted to add a declaration equivalent to what MSVC did "for free," Comeau and GCC nicely resolved the resulting overloading conflict — strike against them. Or is it? As it turns out, the overloaded call occurs earlier in the file than my recommended declaration. If I move the declaration before class mytype { (which requires forward-declaring mytype), then both properly complain about the ambiguity.
Using an overload before it is declared in namespace scope appears to be well and good according to §3.3-3.4 of the Standard. So actually GCC and Comeau were both in the right. The point of declaration is right after the name of the declared object. (And last I checked, self-referential function declarations can still crash GCC.) ADL invokes unqualified lookup into the enclosing namespace at a point immediately before the enclosing class. (3.4.1/8 final bullet, 3.4.1/9, 3.4.2/2a.) If the friend hasn't been declared before the class, it's legitimately not a candidate. (7.3.1.2/3) Isn't C++ a beautiful language?
How keep the simplified example on GCC, but break subsequent code.
friend ostringstream& operator<<(ostringstream& stream, const mytype& a) {
stream << (a.value);//compilation error
return stream;
}
};
ostringstream& operator<<(ostringstream& stream, const mytype& a); // <- here
Following this declaration, it will be impossible to write an int into an ostringstream.
How to break everything uniformly, with simpler declaration semantics.
class mytype; // <- here
// and here:
inline ostringstream& operator<<(ostringstream& stream, const mytype& a);
class mytype {
public:
Following this declaration, it will be impossible to write an int into an ostringstream… including the friend declarations inside class mytype {}.
Actual solution.
The stream classes are supposed to be indistinguishable. If you really want to determine whether a given stream feeds a string in memory (and you shouldn't), it's best to look at its internal streambuf object, returned by rdbuf(), which actually performs the I/O gruntwork. Even a generic ostream object can have ostringstream functionality if given a stringbuf.
if ( typeid( stream.rdbuf() ) == typeid( stringbuf * ) ) {
// this is effectively a stringstream
} else {
// not a stringstream
}
There is an overload ambiguity in the call to operator<< in the ostringstream overload.
stream << a.value;
There are a number of operator<< overloads that are members of the ostream class, which is a base class of ostringstream. One of these is declared as:
ostream& ostream::operator<<(int);
This overload is an exact match for the right-hand side (a.value is an int) but requires a derived-to-base conversion on the left-hand side (stream is an ostringstream, which is derived from ostream).
However, there is also your ostringstream overload:
ostringstream& operator<<(ostringstream&, const mytype&);
This overload is an exact match for the left-hand side (stream is an ostringstream), and a user-defined converting constructor (your mytype(int) constructor) can be used to convert a.value (an int) to a mytype.
Since one overload matches the first argument better and the other overload matches the second argument better, there is an ambiguity. You can fix this either by:
Explicitly converting the left-hand side to an ostream (using (ostream&)stream = a.value;), or
Remove the user-defined conversion by making the constructor explicit.