ostream operator << in Namespace hides other ostream::operator [duplicate] - c++

This question already has answers here:
Calling a function overloaded in several namespaces from inside one namespace
(3 answers)
Closed 4 years ago.
Using gcc version 5.2.0 (GCC) with --std=c++14, the following code does not compile anymore, if the commented out operator ostream in namespace MyNamespace is uncommented. Is this a bug or a feature? (Compile with g++ -c --std=c++14 x.cxx)
#include <string>
#include <iostream>
typedef std::pair<std::string, std::string> StringPair;
std::ostream& operator<<( std::ostream&, const StringPair &pair) {
std::cout <<pair.first<<"."<<pair.second;
}
namespace MyNamespace {
class MyClass {};
//std::ostream& operator<< (std::ostream&, const MyClass &);
void xxx ();
}
void MyNamespace::xxx () {
StringPair pair;pair.first="1";pair.second="2";
std::cout <<pair<<std::endl;
}
The error-message i get with the operator << uncommented is:
x.cxx: In function ‘void MyNamespace::xxx()’:
x.cxx:18:13: error: no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream<char>}’ and ‘StringPair {aka std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >}’)
std::cout <<pair<<std::endl;
^

As stated here, this is an example of name hiding. By defining operator<< in namespace MyNamespace all the definitions from the higher namespaces (like global) are hidden.
Note that as stated here:
[...]this feature doesn't interfere with Koenig lookup [...], so IO operators from std:: will still be found.
(details about Koenig lookup)
The solution is to refer to the overload in the other namespace with the using directive, as described here and here. This was mentioned in the comments by Michael Nastenko.
Thus using ::operator<<;, with :: referring to the global namespace.
Thus the code will become:
#include <string>
#include <iostream>
typedef std::pair<std::string, std::string> StringPair;
std::ostream& operator<<(std::ostream& os, const StringPair &pair) {
os << pair.first << '.' << pair.second;
return os;
}
namespace MyNamespace {
class MyClass {};
using ::operator<<;
std::ostream& operator<< (std::ostream&, const MyClass &);
void xxx();
}
void MyNamespace::xxx() {
StringPair pair("1","2");
std::cout<<pair<<std::endl;
}
int main() {
MyNamespace::xxx();
return 0;
}
example on Coliru

Related

How do you make a fold expression with custom operator <<?

I am trying to make a print function based on parameter pack and fold expression. My implementation fails to compile on clang 10.0. Here is the code:
#include <iostream>
#include <set>
std::ostream &operator<<(std::ostream &strm, const std::set<int> &set) {
strm << set.size();
return strm;
}
template <typename... Args> void Print(std::ostream &strm, Args &&... args) {
(strm << ... << args);
}
int main(int, char **) {
std::set<int> my_set;
Print(std::cout, my_set);
}
and here is the compiler output
#1 with x86-64 clang 10.0.0
<source>:10:12: error: call to function 'operator<<' that is neither visible in the template definition nor found by argument-dependent lookup
(strm << ... << args);
^
<source>:15:3: note: in instantiation of function template specialization 'Print<std::set<int, std::less<int>, std::allocator<int> > &>' requested here
Print(std::cout, my_set);
^
<source>:4:15: note: 'operator<<' should be declared prior to the call site
std::ostream &operator<<(std::ostream &strm, const std::set<int> &set) {
^
1 error generated.
Compiler returned: 1
The same code compiles with gcc 10.1. Is this a compiler bug (or missing feature), or is my implementation incorrect?
Argument-dependent lookup is not helping you here.
The error message is:
:10:12: error: call to function 'operator<<' that is neither visible in the template definition nor found by argument-dependent lookup
So it's looking for an operator<< to call:
It looks in the definition of std::set - nope, none there.
It looks in namespace std (because that's where std::set lives) - nope, not there, either.
Should it look in the global namespace? I don't know.
Clearly gcc and clang have different opinions about that.

"no match" and "cannot bind lvalue" errors while overloading `operator<<` with `std::wostream` and `std::string`

I've got an error while overloading std::wostream::operator<<() for std::string.
Here is the minimal test case illustrating my problem:
#include <string>
#include <sstream>
inline std::wostream &operator<<(std::wostream &os, const std::string &)
{
return os;
}
class FakeOstream{};
namespace mynamespace {
class FakeClasse1 {
friend inline FakeOstream &operator<<(FakeOstream &out, const FakeClasse1 &) {
return out;
}
};
class FakeClasse2 {
friend inline FakeOstream &operator<<(FakeOstream &out, const FakeClasse2 &) {
return out;
}
};
void test()
{
auto mystring = std::string{u8"mystring"};
std::wostringstream s;
s << mystring; // The errors occur here
}
} // namespace mynamespace
The code can be compiled and executed here: http://cpp.sh/9emtv
As you can see here, there is an overload for operator<< with std::wostream
and std::string. The two fake classes are empty apart from the declaration of
an operator<< with FakeOstream and themselves. The test() function
instantiate an std::wostringstream and feed it a std::string. The fake
fake classes and test function are in a namespace.
This code yields the following error on cpp.sh at the line s << mystring;:
In function 'void mynamespace::test()':
25:10: error: cannot bind 'std::basic_ostream<wchar_t>' lvalue to 'std::basic_ostream<wchar_t>&&'
In file included from /usr/include/c++/4.9/istream:39:0,
from /usr/include/c++/4.9/sstream:38,
from 2:
/usr/include/c++/4.9/ostream:602:5: note: initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = wchar_t; _Traits = std::char_traits<wchar_t>; _Tp = std::basic_string<char>]'
operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
^
When using directly g++ (version 5.3.0 from MSYS2), a no match error is also
displayed:
./tmpbug.cpp: In function 'void mynamespace::test()':
./tmpbug.cpp:25:7: error: no match for 'operator<<' (operand types are 'std::wostringstream {aka std::__cxx11::basic_ostringstream<wchar_t>}' and 'std::__cxx11::basic_string<char>')
s << mystring;
^
In file included from C:/Appli/msys64/mingw64/include/c++/5.3.0/istream:39:0,
from C:/Appli/msys64/mingw64/include/c++/5.3.0/sstream:38,
from ./tmpbug.cpp:2:
C:/Appli/msys64/mingw64/include/c++/5.3.0/ostream:628:5: note: candidate: std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = wchar_t; _Traits = std::char_traits<wchar_t>; _Tp = std::__cxx11::basic_string<char>] <near match>
operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
^
C:/Appli/msys64/mingw64/include/c++/5.3.0/ostream:628:5: note: conversion of argument 1 would be ill-formed:
./tmpbug.cpp:25:10: error: cannot bind 'std::basic_ostream<wchar_t>' lvalue to 'std::basic_ostream<wchar_t>&&'
s << mystring;
^
In file included from C:/Appli/msys64/mingw64/include/c++/5.3.0/istream:39:0,
from C:/Appli/msys64/mingw64/include/c++/5.3.0/sstream:38,
from ./tmpbug.cpp:2:
As far as I know, all the parts of the example are necessary for the errors to
appear. If I comment out the namespace, the fake classes or just one of the
operator<< in the fake classes, the code compile just fine. Moreover, if I
just move one of the fake classes or the test function outside of the namespace,
the code will also compile just fine.
Additionnally, I tried compiling this example on clang 3.7 by using the compiler
from http://cppreference.com, and the code seems to compile without problems.
Is there a problem with my code or is this a GCC bug ? If this is a GCC bug, is
there a workaround ?
This is a bad idea:
inline std::wostream &operator<<(std::wostream &os, const std::string &)
as you should not overload operators on two types in std that do not depend on your own (outside of std or build-in) types. Doing ... doesn't work well. And, in my opinion, shouldn't be allowed.
Regardless, you can generate the same problem with conforming code by simply creating your own namespace notstd and own type notstd::string, then in the global root namespace defining
inline std::wostream &operator<<(std::wostream &os, const notstd::string &)
{
return os;
}
and get the same symptoms. So that doesn't matter much.
Operators are found first via unqualified name lookup, then via argument dependent lookup.
As we have no using statement, unqualified name lookup first looks in the enclosing namespace. If nothing is found, the namespaces containing it (and eventually the file/global namespace) are then searched.
ADL then augments this with operators found via ADL or Koenig lookup -- it looks in the namespaces of the arguments and their template parameters.
Now, the friend operator<< you defined do live in the namespace their class contains, but they are usually difficult to find.
Somehow your double-declaration of friend operator<< is making your code find them, and stop looking into the global namespace for a <<.
To me this looks like a bug. Neither of those "Koenig operators" should be visible to bog-standard unqualified name lookup with types unrelated to the classes they are "contained" in.
MCVE:
#include <iostream>
#include <sstream>
namespace notstd {
struct string {};
}
inline void operator<<(std::wostream &os, const notstd::string &){ return; }
class FakeOstream{};
namespace mynamespace {
class UnusedClass1 {
friend inline void operator<<(FakeOstream &out, const UnusedClass1 &) { return; }
};
class UnusedClass2 {
// comment this line out and the code compiles:
friend inline void operator<<(FakeOstream &out, const UnusedClass2 &) { return; }
};
void test() {
auto mystring = notstd::string{};
std::wostringstream s;
s << mystring; // The errors occur here
}
} // namespace mynamespace
int main(){}
live example.
#T.C. found what appears to be this bug being fixed:
test code
fix in gcc

Why does this C++ generic function work by reference but doesn't work by value? [duplicate]

#include <iostream>
using namespace std;
template<typename T>
T max(T lhs, T rhs)
{
return lhs < rhs ? rhs : lhs;
}
template<>
int max<int>(int lhs, int rhs)
{
return lhs < rhs ? rhs : lhs;
}
int main()
{
cout << max<int>(4, 5) << endl;
}
~/Documents/C++/boost $ g++ -o testSTL testSTL.cpp -Wall
testSTL.cpp: In function ‘int main()’:
testSTL.cpp:18:24: error: call of overloaded ‘max(int, int)’ is ambiguous
testSTL.cpp:11:5: note: candidates are: T max(T, T) [with T = int]
/usr/include/c++/4.5/bits/stl_algobase.h:209:5: note: const _Tp& std::max(const _Tp&, const _Tp&) [with _Tp = int]
How do I correct this error?
It's all because of your using namespace std;. Remove that line.
By that using-directive, you bring std::max (which must be somehow included via iostream) into the global scope. Therefore the compiler doesn't know which max to call - ::max or std::max.
I hope this example will be a good scarecrow for those who think that using directives come at no cost. Weird errors are one side effect.
I guess the compiler can't work out whether to use std::max or your max, because you've got a using namespace std; and both your max and the std::max fit the bill
You're colliding with std::max(). Rename it to something else like mymax and it will work.
You have both your max and std::max. The compiler doesn't know which one you intended to call.
You can tell it by calling ::max(4,5) or std::max(4,5), or - even better - not have using namespace std in the file.
That's because there's already std::max template function defined.
Remove the 'using namespace std' and add 'std::' where needed., or use '::max'.
The problem is that there is already a function named 'max' defined by std. To fix this, rename your function to something else, like this:
#include <iostream>
using namespace std;
template<typename T>
T mymax(T lhs, T rhs)
{
return lhs < rhs ? rhs : lhs;
}
template<>
int mymax<int>(int lhs, int rhs)
{
return lhs < rhs ? rhs : lhs;
}
int main()
{
cout << mymax<int>(4, 5) << endl;
return 0;
}

Why does outputting a class with a conversion operator not work for std::string?

This works, printing 1:
#include <iostream>
struct Int {
int i;
operator int() const noexcept {return i;}
};
int main() {
Int i;
i.i = 1;
std::cout << i;
}
However, this fails to compile on GCC 4.8.1:
#include <iostream>
#include <string>
struct String {
std::string s;
operator std::string() const {return s;}
};
int main() {
String s;
s.s = "hi";
std::cout << s;
}
Here are the relevant parts of the error:
error: no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream}’ and ‘String’)
std::cout << s;
snip
template std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::basic_string<_CharT, _Traits, _Alloc>&)
operator<<(basic_ostream<_CharT, _Traits>& __os,
/usr/include/c++/4.8/bits/basic_string.h:2753:5: note: template argument deduction/substitution failed:
main.cpp:25:18: note: ‘String’ is not derived from ‘const std::basic_string<_CharT, _Traits, _Alloc>’
std::cout << s;
I only use std::cout and std::string, which have the same template arguments. I'm really not sure why this wouldn't be able to pick up the implicit conversion like it did for Int. Why does it work with int, but not std::string?
That operator is a free template function. User defined conversions do not get checked when matching against a template function arguments, it instead uses type pattern matching (substitution).
In theory a SFINAE overload using std::is_convertable<> would be able to do what you want, but that technique was not used when operator<< that outputs a std::string to a basic_ostream<char> was defined.
A manual overload to output your class to basic_ostream<...> will fix your problem.
I would do this:
struct String {
std::string s;
operator std::string() const {return s;}
friend std::ostream& operator<<( std::ostream& os, String const& self) {
return os<<self.s;
}
};
which has the added benefit of not creating a wasted copy.
The << operator seems to have a pool of overloads with types other than std::string.
as I have seen by using the clang++ compiler.
The compiler does the implicit conversion from String to std::string but it does not match any of the defined << operators.
If you define the << operator for std::string it will work
#include <iostream>
#include <string>
std::ostream& operator<<(std::ostream& s, const std::string& str)
{
s << str.c_str();
return s;
}
struct String {
std::string s;
operator std::string() const {return s;}
};
int main() {
String s;
s.s = "hi";
std::cout << s;
}
You can find more details on the same issue here: http://forums.codeguru.com/showthread.php?432227-RESOLVED-Implicit-conversion-to-std-string
As seen in one post;
The problem is the operator<< here is a template and no template instantiations can be made for the type TestClass since the user defined conversions are probably not being considered in argument deduction for templates for implicit instantiations (atleast I could not find in section 14.7.1 (Implicit instantiation). This results in an empty overload set for the call "std::cout << obj << '\n';" and hence the error. It does not matter if an instantiation already happened or not. Template candidates are chosen into overload set on exact matches (except for array to pointer decay and const qualification - http://groups.google.co.in/group/com...29910b6?hl=en&).
When you provide an explicit overload operator<< with type std::string, it is non-template and adds up in the overload set and hence invoking the implicit conversion while doing overload resolution/a callable match.

A way to print of map of multimaps?

I'm trying to overload operator<<, and it drove me crazy:
std::ostream& operator<<(std::ostream & lhs, TuringMachine::TRTable& rhs){
for(auto& statePtr : rhs){
lhs << statePtr.first->getLabel().toStdString();
for(auto& charPtr: statePtr.second){
//lhs << '\t';
lhs << charPtr.first.toAscii() ;
//lhs << 'b ';
lhs << charPtr.second.getState().getLabel().toStdString() << std::endl;
}
}
return lhs;
}
TRTable is a typedeffor std::map<State*, std::multimap<QChar, Transition>>. Statehas its label as a QString hence the call to .toStdString().
In another class I call std::cout << machine->table << std::endl; with machine beeing a TuringMachine* and this gives me
error: cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'
What am I doing wrong? Why &&?
EDIT: using g++ 4.6 and -std=c++0x
In which namespace did you declare the operator<<? Since TRTable is a typedef ADL does not apply, so the operator<< is searched only in namespace std by ADL, since this is where the actual class is defined. So you might have to use the namespace where you defined the operator<< when you want to use it.
lhs should have type std::ostream &. No const.
rhs should be const TuringMachine::TRTable&:
std::ostream& operator<<(std::ostream& lhs, const TuringMachine::TRTable& rhs)