I have a template function like this one
#include <list>
#include <iostream>
template<typename T>
std::ostream& operator<<(std::ostream& out, const std::list<T>& list){
out << "[";
if(!list.empty()){
typename std::list<T>::const_iterator it = list.cbegin();
out << *it;
for (++it; it != list.cend(); ++it){
out << ", ";
out << *it;
}
}
out << "]";
return out;
}
And some template class with nested classes
namespace my{
template<
typename T,
typename U = size_t
>
class graph{
public:
typedef T dist_t;
typedef U node_t;
class node_pt;
typedef struct arc_t{
node_pt* from = nullptr;
node_pt* to = nullptr;
dist_t weight;
} arc_t;
typedef struct arc_pt{
arc_t arc;
} arc_pt;
typedef struct node_pt{
node_t node;
} node_pt;
class arc_iterator{
public:
arc_pt* pt = nullptr;
public:
arc_pt* operator->() const{
return pt;
}
friend std::ostream& operator<< (std::ostream &out, const arc_iterator& it) {
out << "(" << it->arc.from->node << "," << it->arc.to->node << "," << it->arc.weight << ")";
return out;
}
};
class node_iterator{
public:
node_pt* pt = nullptr;
public:
node_t operator *() const{
return pt->node;
}
friend std::ostream& operator<< (std::ostream &out, const node_iterator& it) {
out << *it;
return out;
}
};
};
}
Some code to reproduce the problem
namespace my{
namespace test{
void run(){
typedef my::graph<size_t> graph_t;
std::list<graph_t::node_t> l1;
std::list<graph_t::dist_t> l2;
std::list<graph_t::node_iterator> l3;
std::list<graph_t::arc_iterator> l4;
std::cout << l1 << std::endl;
std::cout << l2 << std::endl;
std::cout << l3 << std::endl;
std::cout << l4 << std::endl;
}
}
}
int main(){
my::test::run();
}
The problem is it doesn't compile if I define the two friend methods. If I only define one method and comment one of the iterator list printing it works.
The error I'm getting is
src/OTest_Graph.cpp: In member function ‘virtual void my::test::TestGraph::run()’:
src/OTest_Graph.cpp:59:53: error: cannot bind ‘std::basic_ostream<char>’ lvalue to ‘std::basic_ostream<char>&&’
In file included from /usr/include/c++/4.7/iostream:40:0,
from h/OTest_Graph.h:4,
from src/OTest_Graph.cpp:1:
/usr/include/c++/4.7/ostream:600:5: error: initializing argument 1 of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = std::list<my::graph<long unsigned int>::node_iterator, std::allocator<my::graph<long unsigned int>::node_iterator> >]’
Can anyone tell me what's going on here?
Well, the code compiles and runs for me in clang++. Can't try with g++ on this computer.
Edit: Actually, it compiles with g++ as well, which makes sense because you only use the operator<< in the main which is in the global namespace. I assume your actual code is different \Edit
But I'm familiar with the "ostream lvalue can't bind to ostream&&" error
How to explain. There is a problem in providing operator<< between ostreams and any std class (like list in your example, but I found it with vector)
Mostly it works, but when the operator is called from a namespace (like your my namespace) it breaks.
Why? Because "where do I look for this operator<< member"? See, there might be a lot of operator<< between ostreams and lists - each in a different namespace. So where does the compiler look for it?
It looks in the namespaces of each on its operands (in your case - both are from std). And sometimes in the namespace of the caller (which in your case is my).
I say "sometimes" because according to the standard it shouldn't, but g++ does it anyway. clang++ doesn't - but looks in the global namespace instead (hence why it worked for me)
Ideally, you'd want to put the operator<< inside the std namespace (try it - it will work). BUT - that is against the standard. You are not allowed to do that. You can put it in the my namespace and it should work find in g++, but not in other compilers.
It's a problem. I "solved" it by creating a wrapper - a class that exists in my own namespace and only holds a reference to the std class - and can be printed.
template<class T> struct OutList<T>{
const std::list<T> &lst;
OutList(const std::list &l):lst(l){}
};
template<class T> OutList<T> outlist(const std::list<T> &lst){return OutList<T>(lst);}
std::ostream &operator<<(std::stream &out,const OutList<T> &lst){...}
....
std::cout << "list= "<<outlist(list)<<std::endl;
It isn't pretty, but that's all I found...
I had the same problem with the following operator, declared in the global namespace:
template <typename T>
std::ostream & operator << (std::ostream &os, const std::vector<T> &vector);
…when called from a function declared in a named namespace:
std::ostream & operator << (std::ostream &os, const Foo &foo) {
return os << foo.items; // error
}
…where Foo::items is a std::vector.
g++ gives the infamous error:
error: cannot bind 'std::basic_ostream<char>' lvalue to 'std::basic_ostream<char>&&'
The error arises because C++11 introduced a catch-all std::operator << template, which the comment in <ostream> describes as a "generic inserter for rvalue stream." The compiler does not find the global ::operator << template because argument-dependent lookup finds the std::operator << template first.
A simple and correct fix is to bring the global operator into the local scope by a using declaration:
std::ostream & operator << (std::ostream &os, const Foo &foo) {
using ::operator <<;
return os << foo.items; // OK
}
The error depends on the version of the standard library, see #matt-whitlock's answer.
A solution for g++ 4.7 :
Instead of
std::cout << l1 << std::endl;
std::cout << l2 << std::endl;
std::cout << l3 << std::endl;
std::cout << l4 << std::endl;
use
::operator<<(std::cout, l1) << std::endl;
::operator<<(std::cout, l2) << std::endl;
::operator<<(std::cout, l3) << std::endl;
::operator<<(std::cout, l4) << std::endl;
Related
I have written code that detects if one object can be streamed into an std::ostream. However, while it works in clang, it fails in gcc. After simplifying the code, the problem seems to occur when two classes have operator<< defined in different namespaces.
Below is the (simplified) code (and here it is on godbolt):
#include <iostream>
namespace test_ns {
// Define two (trivial) classes.
class Class1 { };
class Class2 { };
// First class has ostream operator defined in namespace test_ns
std::ostream & operator<<(std::ostream & out, const Class1 & v) {
return out << "Class1 Output!";
}
}
// Second class as ostream operator defined in global namespace.
std::ostream & operator<<(std::ostream & out, const test_ns::Class2 & v) {
return out << "Class2 Output!";
}
namespace test_ns {
// Simple template that always evaluates to bool (for SFINAE-based reflection)
template <typename EVAL_TYPE> using bool_decoy = bool;
// Two version of HasPrint that test the operator<< into ostream.
// First version preferred if << works...
template <typename T>
bool HasPrint(bool_decoy<decltype( std::declval<std::ostream&>() << std::declval<T>() )>) {
return true;
}
// Second version as a fallback.
template <typename T>
bool HasPrint(...) {
return false;
}
}
int main()
{
std::cout << test_ns::HasPrint<test_ns::Class2>(true) << std::endl;
}
Here is the error I receive in gcc 9.1:
<source>: In instantiation of 'bool test_ns::HasPrint(test_ns::bool_decoy<decltype ((declval<std::basic_ostream<char, std::char_traits<char> >&>() << declval<T>()))>) [with T = test_ns::Class2; test_ns::bool_decoy<decltype ((declval<std::basic_ostream<char, std::char_traits<char> >&>() << declval<T>()))> = <type error>]':
<source>:40:55: required from here
<source>:26:68: error: no match for 'operator<<' (operand types are 'std::basic_ostream<char>' and 'test_ns::Class2')
26 | bool HasPrint(bool_decoy<decltype( std::declval<std::ostream&>() << std::declval<T>() )>) {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~
(followed by a long list of candidates)
While I can (and will) refactor the code to circumvent this issue, I don't fully understand what is going wrong here. Am I improperly defining the operators, or is this a problem with gcc?
The simple answer, as hinted by NathanOliver, is that your operator<< in the global namespace isn’t found by ADL, and it can’t be found by unqualified lookup from test_ns::HasPrint because of test_ns::operator<<. The interesting question is why Clang finds it anyway. I can only assume that decltype is somehow confusing it.
I want to test whether a class is streamable to ostream& by seeing whether an overload for operator<< is provided. Based on these posts, I tried to write another version using C++11. This is my attempt:
#include <iostream>
#include <type_traits>
namespace TEST{
class NotDefined{};
template<typename T>
NotDefined& operator << (::std::ostream&, const T&);
template <typename T>
struct StreamInsertionExists {
static std::ostream &s;
static T const &t;
enum { value = std::is_same<decltype(s << t), NotDefined>() };
};
}
struct A{
int val;
friend ::std::ostream& operator<<(::std::ostream&, const A&);
};
::std::ostream& operator<<(::std::ostream& os, const A& a)
{
os << a.val;
return os;
}
struct B{};
int main() {
std::cout << TEST::StreamInsertionExists<A>::value << std::endl;
std::cout << TEST::StreamInsertionExists<B>::value << std::endl;
}
But this fails to compile:
test_oper.cpp:40:57: error: reference to overloaded function could not be resolved; did you mean to call it?
std::cout << TEST::StreamInsertionExists<A>::value << std::endl;
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:1020:1: note:
possible target for call
endl(basic_ostream<_CharT, _Traits>& __os)
test_oper.cpp:30:17: note: candidate function not viable: no known conversion from 'TEST::NotDefined' to '::std::ostream &'
(aka 'basic_ostream<char> &') for 1st argument
::std::ostream& operator<<(::std::ostream& os, const A& a)
test_oper.cpp:15:15: note: candidate template ignored: couldn't infer template argument 'T'
NotDefined& operator << (::std::ostream&, const T&);
However, if I replace the line
enum { value = std::is_same<decltype(s << t), NotDefined>() };
with
static const bool value = std::is_same<decltype(s << t), NotDefined>();
then everything compiles.
Why is there such a difference between the enum and the bool?
value is an enum of anonymous name in StreamInsertionExists<T>. When you try to do:
std::cout << StreamInsertionExists<T>::value;
The compiler is doing overload lookup on operator<<(std::ostream&, StreamInsertionExists<T>::E). In the typical case, it'd do integral promotion on the enum and stream it as int. However, you additionally defined this operator:
template<typename T>
NotDefined& operator << (std::ostream&, const T&);
That is a better match for the enum than the int version (Exact Match vs integral promotion), so it is preferred. Yes, it's a function template, but non-templates are only preferred if the conversion sequences match - and in this case they don't.
Thus, this line:
std::cout << TEST::StreamInsertionExists<A>::value << std::endl;
which is:
operator<<(operator<<(std::cout, TEST::StreamInsertionExists<A>::value), std::endl);
And the inner most operator<< call will use your NotDefined& template. Thus, the next step would be to find an appropriate function call for:
operator<<(NotDefined&, std::endl);
and there is no such overload for operator<< hence the error.
If you change value to be bool, there is no such problem because there is an operator<< that takes bool exactly: #6. That said, even with bool, your trait is still incorrect as it always returns false. Your NotDefined version actually returns a reference, so you'd have to check against that. And also, NotDefined& means not defined, so you'd have to flip the sign:
static const bool value = !std::is_same<decltype(s << t), NotDefined&>();
However, this is particularly error prone. Now cout << B{}; instead of failing to compile would instead give you a linker error, and cout << B{} << endl; gives you the same confusing overload error involving endl instead of simply statying that you can't stream a B.
You should prefer to just do:
template <typename...>
using void_t = void;
template <typename T, typename = void>
struct stream_insertion_exists : std::false_type { };
template <typename T>
struct stream_insertion_exists<T, void_t<
decltype(std::declval<std::ostream&>() << std::declval<T>())
> > : std::true_type { };
I am having trouble to specialize an overloaded << operator template:
The general template is defined as follows:
template<typename DocIdType,typename DocType>
std::ostream & operator << (std::ostream & os,
const Document<DocIdType,DocType> & doc)
{
[...]
}
The general template works fine. Now I want to specialize the second template parameter. I've tried:
template<typename DocIdType>
std::ostream & operator << <DocIdType,std::string> (std::ostream & os,
const Document<DocIdType,std::string> & doc)
{
[...]
}
When I try to compile this piece of code I get the following compiler error:
"C2768: Illegal use of explicit template arguments"
Can somebody tell me what I am doing wrong?
I could be wrong, but off the top of my head I'd say function templates can't be partially specialized.
Even if they could, prefer straight overloading.
See also Why Not Specialize Function Templates? (by Herb Sutter)
See it Live on Coliru
#include <iostream>
#include <string>
template<typename DocIdType,typename DocType>
struct Document {};
template<typename DocIdType>
std::ostream & operator << (std::ostream & os, const Document<DocIdType,std::string> & doc) {
return os << "for string";
}
template<typename DocIdType,typename DocType>
std::ostream & operator << (std::ostream & os, const Document<DocIdType,DocType> & doc) {
return os << "for generic";
}
using namespace std;
int main(int argc, char *argv[])
{
std::cout << Document<struct anything, std::string>() << "\n";
std::cout << Document<struct anything, struct anything_else>() << "\n";
}
Prints
for string
for generic
I have the following class:
namespace {
class MimeLogger : public std::ostringstream
{
public:
MimeLogger()
{}
~MimeLogger()
{
LOGEVENT( logModuleWSE, logEventDebug, logMsgWSETrace1, str() );
}
};
}
When I do this:
MimeLogger() << "Hello " << "World";
The first "Hello " string is treated as a void*. If I debug the code, "Hello " is passed into std::basic_ostream::operator<< (void const*) and prints as a pointer value, not a string. The second string, "World" is properly passed into the global overloaded << operator that takes a char const*.
I expect both usages of the << operator to resolve to the same overload, but this does not happen. Can someone explain, and maybe propose a fix?
Thanks in advance.
Update
I neglected to mention that I'm stuck with C++03, but I'm glad that some people covered both the C++03 and C++11 cases.
C++03: For the expression MimeLogger() << "Hello ", the template function
template <typename charT, class traits>
std::basic_ostream<charT, traits>& std::operator<< (
std::basic_ostream<charT, traits>& os,
const char* cstr);
is not considered during overload resolution because the temporary MimeLogger() may not be bound to a non-const reference. The member function overloads do not have this problem because the rules for the implicit parameter do allow binding to a temporary.
If you can use a compiler with support for C++11 rvalue-references, this should work as you intended, because the C++11 library provides an additional overload
template <typename charT, class traits, typename T>
std::basic_ostream<charT, traits>& std::operator<< (
std::basic_ostream<charT, traits>&& os,
const T& x ); // { os << x; return os; }
which allows temporary streams to be used left of << as though they were not temporary.
(I did try a test program with g++ and got different results without and with -std=c++0x.)
If you cannot use a C++11 friendly compiler, adding this to the public section of class MimeLogger is a workaround that will do what you want with C++03:
template<typename T>
MimeLogger& operator<<(const T& x)
{
static_cast<std::ostringstream&>(*this) << x;
return *this;
}
using std::ostringstream::operator<<;
The using-declaration makes sure the member overloads from the standard library are also visible from MimeLogger. In particular, without it manipulators like std::endl don't work with the template operator, since std::endl is itself a function template, and that's too much template type deduction to expect from C++. But things are fine as long as we're sure not to hide the ostream member that makes the function manipulators work (27.7.3.6.3):
namespace std {
template <typename charT, class traits>
class basic_ostream : /*...*/ {
public:
basic_ostream<charT, traits>& operator<<(
basic_ostream<charT,traits>& (*pf)(basic_ostream<charT,traits>&));
};
}
How about using containment of std::ostringstream ?
class MimeLogger
{
private:
std::ostringstream oss_m;
public:
MimeLogger()
{
}
~MimeLogger()
{
std::cout << __FILE__ << "(" << __LINE__ << "):" << oss_m.str() << "\n";
}
template<typename Type>
MimeLogger& operator<<(const Type& t)
{
oss_m << t;
return *this;
}
};
void LogDemo()
{
MimeLogger logger;
logger << "Hello " << "World!!\n";
MimeLogger() << "Hello " << "StackOverflow!!\n";
}
In the sample code below, it shows that boost::tuple can be created implicitly from the first template argument.
Because of that I am not able to write a << operator as it becomes ambiguous.
Also I don't understand why ostringstream& << float is also ambiguous. This does not have any implicit construction. Why does this also give ambiguous error?
#include <iostream>
#include <boost/tuple/tuple.hpp>
#include <sstream>
#include <string>
using namespace std;
class Myclass
{
};
typedef boost::tuple<int,float,Myclass> Mytuple;
ostringstream& operator<<(ostringstream& os_, Mytuple tuple_)
{
float f = tuple_.get<1>();
//os_ << (int)tuple_.get<0>(); // Error because int is implicitly converted into Mytuple. WHYY?
//os_ << tuple_.get<1>(); // No Clue Why this is ambiguous.
//os_ << tuple_.get<2>(); // Error because no matching operator. Fine.
return os_;
}
int main()
{
Mytuple t1;
t1 = 3; // Working because int is implicitly converted into Mytuple!! WHY?
//t1 = 3.0f; // Error because no matching constructor. Fine.
return 0;
}
Error Mesasge:
tupleTest2.C:18: error: ISO C++ says that these are ambiguous, even
though the worst conversion for the first is better than the worst
conversion for the second:
The problem is not with the tuple, but with your operator. This works fine :
ostream& operator<<(ostream& os_, Mytuple tuple_)
{
os_ << tuple_.get<0>(); // Error because int is implicitly converted into Mytuple. WHYY?
os_ << tuple_.get<1>(); // No Clue Why this is ambiguous.
//os_ << tuple_.get<2>(); // Error because no matching operator. Fine.
return os_;
}
The problem is that the ostringstream inherit operator<< from ostream, which has this signature : ostringstream& operator<<(ostringstream& os_, Mytuple tuple_) is allowed. Then the
ostream& operator<<(ostream& os, T t)
(change T with all available types in c++, see operator<< reference page
EDIT
Here is a simplified example (without a tuple) :
ostringstream& operator<<(ostringstream& os_, Mytuple tuple_)
{
const int i = tuple_.get<0>();
os_ << i; // error in this line
return os_;
}
and the error is now :
dfg.cpp: In function ‘std::ostringstream& operator<<(std::ostringstream&, Mytuple)’:
dfg.cpp:18: error: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second:
/usr/lib/gcc/i386-redhat-linux/4.3.0/../../../../include/c++/4.3.0/bits/ostream.tcc:111: note: candidate 1: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = char, _Traits = std::char_traits<char>]
dfg.cpp:14: note: candidate 2: std::ostringstream& operator<<(std::ostringstream&, Mytuple)
The above error message says : it is not possible to choose between two operators operator<<(ostream&,...) and operator<<(ostringstream&,...). This also raises another question : why on earth do you needoperator<<(ostringstream&,...)`?
When you write
os << tuple_.get<0>();
there is no function that matches both parameters. Instead the compiler has a choice to apply an implicit conversion on either parameter
std::ostream << int
or
std::ostringstream << MyTuple
The latter would happen with the boost::tuple constructor that can take any number of arguments up to number of tuple elements. (And with float it fails, because float is convertible to int.)
When overloading stream operators, use the base class as the left hand side (ostream or even basic_ostream<CharT, Traits>.
Edit: You could disambiguate the call by casting the first argument.
ostringstream& operator<<(ostringstream& os_, Mytuple tuple_)
{
static_cast<std::ostream&>(os_) << tuple_.get<0>();
static_cast<std::ostream&>(os_) << tuple_.get<1>();
static_cast<std::ostream&>(os_) << tuple_.get<2>(); // Error because no matching operator. Fine.
return os_;
}
However, overloading the operator with ostringstream is still a bad idea, because it won't work with operator chaining.
MyTuple a, b;
ostringstream ss;
ss << a << ' ' << b;
will invoke:
1) ostringstream& operator<<(ostringstream& os_, Mytuple tuple_)
2) ostream& ostream::operator<<(char)
3) ostream& operator<<(ostream&&, boost::tuple<int,float,Myclass>
All those people telling you to use ::std::ostream for the type instead of ::std::ostringstream are absolutely correct. You shouldn't be using ::std::ostringstream that way.
But my main beef with your code is the distressing lack of generality. It only works for one particular tuple type, and not all of them.
So I wrote an operator << for ::std::tuple in C++0x that works for any tuple who's members can be individually written using operator <<. It can probably be translated relatively easily to work with Boost's tuple type. Here it is:
template < ::std::size_t fnum, typename tup_type>
void print_fields(::std::ostream &os, const tup_type &val)
{
if (fnum < ::std::tuple_size<tup_type>::value) {
::std::cerr << "Fred " << fnum << '\n';
os << ::std::get<fnum, tup_type>(val);
if (::std::tuple_size<tup_type>::value > (fnum + 1)) {
os << ", ";
}
print_fields<fnum + 1, tup_type>(os, val);
}
}
template < ::std::size_t fnum, typename... Elements>
class field_printer;
template <typename... Elements>
class field_printer<0, Elements...> {
public:
typedef ::std::tuple<Elements...> tup_type;
static void print_field(::std::ostream &os, const tup_type &val) {
}
};
template < ::std::size_t fnum, typename... Elements>
class field_printer {
public:
typedef ::std::tuple<Elements...> tup_type;
static void print_field(::std::ostream &os, const tup_type &val) {
constexpr auto tupsize = ::std::tuple_size<tup_type>::value;
os << ::std::get<tupsize - fnum, Elements...>(val);
if (fnum > 1) {
os << ", ";
}
field_printer<fnum - 1, Elements...>::print_field(os, val);
}
};
template <class... Types>
::std::ostream &operator <<(::std::ostream &os, const ::std::tuple<Types...> &val)
{
typedef ::std::tuple<Types...> tup_type;
os << '(';
field_printer< ::std::tuple_size<tup_type>::value, Types...>::print_field(os, val);
return os << ')';
}
This prints out the tuple as "(element1, element2, ...elementx)".