Why doesn't the following code compile?
#include <iostream>
namespace X
{
inline std::wostream & operator<<(std::wostream & stm, int a)
{
stm << L"int";
return stm;
}
}
namespace Y
{
class A
{
};
}
inline std::wostream & operator<<(std::wostream & stream, const Y::A & msg)
{
stream << L"A";
return stream;
}
namespace X
{
void f()
{
Y::A a;
std::wcout << a;
}
}
and why removing operator << in namespace X, makes the code compile? Try to comment it out, for example:
namespace X
{
//inline std::wostream & operator<<(std::wostream & stm, int a)
//{
// stm << L"int";
// return stm;
//}
}
what is the dependency between these operators?
see live example.
EDIT1:
The only guess I have is that the operator declared in the same namespace where it is used hides the operators from other namespaces somehow, but I never heard about that before...
EDIT2:
Actually in my project the second operator is in namespace Z (but not global):
...
namespace Z
{
inline std::wostream & operator << (std::wostream & stream, const Y::A & msg)
{
stream << L"A";
return stream;
}
}
namespace X
{
void f()
{
using namespace Z;
Y::A a;
std::wcout << a;
}
}
that results in the same compiler error.
This behavior is actually expected in C++, in order to avoid unexpected behaviors introduced by different overloads in different namespaces.
This is called name hiding.
You can read a really good answer on the subject here: https://stackoverflow.com/a/1629074/182676
So overloads in different namespaces will hide each other.
You can fix this by making the correct overload visible to the compiler with using:
Y::A a;
using Z::operator<<;
std::wcout << a;
NOTE: lookup of overloaded operators is substantially different to class member function lookup as suggested by other comments/answers. See this answer for an introduction to the name lookup rules for overloaded operators.
In your first example, std::wcout << a inside X::f(), name lookup finds:
Qualified lookup for member functions of the left operand: std::wostream has a member function operator<<.
Unqualified lookup: the current scope is in namespace X, so X::operator<< is found, and we stop here. This stage only goes up to check parent namespaces if the name is not found.
Argument-dependent lookup: the arguments are std::wcout and Y::a, so the ADL namespaces are std and Y.
So the overload set consists of:
(QL) All member functions std::wostream::operator<<.
(UL) All free functions X::operator<<.
(ADL) All free functions std::operator<<
(ADL) All free functions Y::operator<< (or would, if there were any).
and nothing else.
None of those find a match for argument type Y::A so compilation fails.
When you remove X::operator<<, then the unqualified lookup step finds nothing in X so it looks in the parent namespace, recursively. Then ::operator<< is found and that function goes into the overload set, and compilation succeeds.
To avoid this problem, the usual procedure is to put free overloaded operators of user-defined types into the same namespace as the type was defined, so in this case you would do:
namespace Y
{
inline std::wostream & operator<<(std::wostream & stream, const A & msg) { .... }
}
and then the ADL step would find this function even though the unqualified lookup step also finds X::operator<<.
In your second example the exact meaning of using namespace Z; is:
During unqualified name lookup, the names appear as if they were declared in the nearest enclosing namespace which contains both the using-directive and the nominated namespace.
The nearest enclosing namespace containing both X and Z is the global namespace, so the names behave as if in the global namespace for the unqualified lookup phase.
Therefore the process is not substantially different to my analysis for your first case, and only X::operator<< is found by unqualified lookup. Again, this would be fixed by including the desired overload in Y so that it is found by ADL.
Related
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.
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.
I'm trying to define an equality operator for a type T defined in another namespace, and then use the equality operator on optional<T>. On clang (Apple LLVM 9.1.0), this code:
namespace nsp {
struct Foo {
};
}
bool operator==(const nsp::Foo& a, const nsp::Foo& b);
void foo() {
optional<nsp::Foo> a = none;
optional<nsp::Foo> b = none;
if (a == b)
;
}
Results in an error:
/usr/local/include/boost/optional/detail/optional_relops.hpp:29:34: error: invalid operands to binary expression ('const nsp::Foo' and 'const nsp::Foo')
{ return bool(x) && bool(y) ? *x == *y : bool(x) == bool(y); }
~~ ^ ~~
MWE.cpp:40:19: note: in instantiation of function template specialization 'boost::operator==<what3words::engine::nsp::Foo>' requested here
if (a == b)
^
/usr/local/include/boost/optional/detail/optional_relops.hpp:28:6: note: candidate template ignored: could not match 'optional<type-parameter-0-0>' against 'const nsp::Foo'
bool operator == ( optional<T> const& x, optional<T> const& y )
What's happening? My guess is that it's something to do with the Koenig lookup rules...
Immediate fix
Do this:
namespace nsp {
bool operator==(const Foo& a, const Foo& b);
}
to fix your problem.
If you have control over Foo, you can instead do:
namespace nsp {
struct Foo {
friend bool operator==(const Foo& a, const Foo& b) {
return true;
}
};
}
which is optimal if Foo is a template class.
What went wrong with your solution
What is going on here is that optional is in std (or boost or whatever) and in that namespace it tries to do a nsp::Foo == nsp::Foo call.
There is a == that doesn't apply in the ::std namespace, so it won't look in ::; once it finds any == it stops looking, even if the arguments are completely unrelated. It also looks for == in the namespaces associated with the arguments -- in this case ::nsp. But it never looks in :: here either.
When adding operators to a type, always define the operator in the namespace of the type.
Namespaces can be reopened. So if you don't have control over the header file, you can create a new header file with the == in it. This == has to be visible at every point where optional<nsp::Foo>::operator== is invoked or your program is ill formed due to ODR violations (and, in this case, also generates a compiler error, which is useful to avoid heizenbugs).
The long version
When you invoke an operator (or a function), lookup follows a few simple steps.
First it looks around locally (in the local namespace). If it finds anything there, this search stops. (This includes using ns::identifier; names injected into the namespace, but usually not using namespace foo;). This "stop" occurs even if the function or operator won't work for the types in question; any == for any types whatsoever in a namespace stops this search.
If that fails to find a match, it starts looking in enclosing namespaces until it finds the function/operator, or reaches the root namespace. If there are using namespace foo; declarations, the functions/operators in those namespaces are considered to be in the "common parent" namespace of both the using namespace location and the namespace being imported. (So using namespace std; in namespace foo makes it seem like std is in ::, not in foo).
The result generates a collection of candidates for overload resolution.
Next, ADL (argument dependent lookup) is done. The associated namespaces of all function/operator arguments are examined. In addition, the associated namespaces of all the type arguments of the templates are also examined (recursively).
Operators/functions that match the name are collected. For ADL, parent namespaces are not examined.
These two collections of operators/functions are your candidates for overload resolution.
In your case, the namespace where == is called is boost. boost has plenty of == operators (even if they don't apply), so all of the == in boost are candidates.
Next, we examine the namespace of the arguments -- nsp::Foo in this case. We look in nsp and see no ==.
Then we run overload resolution on those. No candidates work, and you get a compiler error.
Now, when you move your user-defined == into namespace nsp, it is then added to the set of == found in the ADL step. And as it matches, it is called.
Overload resolution (what it does with the candidates) is its own complex subject. The short form is that it tries to find the overload that involves the least amount of conversion; and if two cases match exactly as well as each other, it prefers non-template over template and non-variardic over variardic.
There is a lot of detail in "least amount of conversion" and "exactly" that can mislead programmers. The most common is is that converting a Foo lvalue to Foo const& is a small amount of conversion, convering it to template<class T> T&& or T& is no conversion.
Indeed, you should enable ADL by declaring the operator== implementation inside an associated namespace for Foo. This fixes that:
#include <boost/optional.hpp>
namespace nsp {
struct Foo { };
bool operator==(const Foo&, const Foo&) { return false; }
}
int main() {
boost::optional<nsp::Foo> a;
boost::optional<nsp::Foo> b;
return (a == b)? 0 : 1;
}
The following code fails to compile
namespace A {
using C = std::vector<std::string>;
std::ostream& operator << (std::ostream& lhs, const C& rhs) {
lhs << 5;
return lhs;
}
}
int main()
{
A::C f;
std::cout << f;
return 0;
}
with the error
Error C2679 binary '<<': no operator found which takes a right-hand operand of type 'A::C' (or there is no acceptable conversion)
Obviously it cant find the << operator presumably due to considering C to be a class from the std namespace. Is there some way to ensure the compiler finds this operator or otherwise work around the problem?
A::C is just a type alias, and aliases are transparent. They don't "remember" where they came from. When we do argument-dependent lookup and figure out what the associated namespaces are, we only consider the associated namespaces of the types - not the alias that got us there. You can't just add associated namespaces to existing types. The specific associated namespace of f (which is of type std::vector<std::string>) is std, which doesn't have an operator<< associated with it. Since there's no operator<< found using ordinary lookup, nor is there one found using ADL, the call fails.
Now, I said you can't just add associated namespaces to existing types. But you can of course just create new types:
namespace A {
struct C : std::vector<std::string> { };
}
or:
namespace A {
// template parameters are also considered for associated namespaces
struct S : std::string { };
using C = std::vector<S>;
}
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.