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
Related
Assume that I want to implement operator<< for all types. I would do:
template <typename T>
std::ostream& operator<<(std::ostream& out, T&& t) {
return out << "DEFAULT";
}
But this won't work because of ambiguity (in cases where the already specified operator<< is a free function). So I tried to restrict this with a concept:
template <typename T>
concept printable = requires(const T& t, std::ostream& out) {
out << t;
};
This correctly reports that ints, std::strings and whatnot are printable, but std::vectors or some_user_defined_structs (without overloaded <<) are not.
What I wanted was to use this concept with my (overly generic) operator<<:
#include <iostream>
#include <vector>
template <typename T>
concept printable = requires(const T& t, std::ostream& out) {
out << t;
};
template <typename T>
requires (!printable<T>)
std::ostream& operator<<(std::ostream& out, T&& t) {
return out << "DEFAULT";
}
int main() {
std::cout << std::vector<int>();
}
But this lead to:
In instantiation of 'std::ostream& operator<<(std::ostream&, T&&) [with T = const char (&)[8]]':
recursively required from 'std::ostream& operator<<(std::ostream&, T&&) [with T = const char (&)[8]]'
required from 'std::ostream& operator<<(std::ostream&, T&&) [with T = const char (&)[8]]'
required from here
fatal error: template instantiation depth exceeds maximum of 900 (use '-ftemplate-depth=' to increase the maximum)
6 | out << t;
| ~~~~^~~~
compilation terminated.
It seems that there is an instantiation loop. In order to check whether we should use my <<, printable is being checked and by doing so, << is attempted to be generated, which leads to a loop.
Is there any mechanism that would prevent such loop? Can we constrain types in such a way that the template will be generated only if it needs to? As for the use-cases, assume that, for some reason, I never want the compilation to fail when someone tries to << something to std::cout.
You can't provide an operation if and only if the operation isn't provided. That's inherently self-recursive.
What you can do instead is add another layer of indirection. Like so:
template <typename T>
void print(std::ostream& os, T&& t) {
if constexpr (printable<T>) {
os << t;
} else {
os << "DEFAULT";
}
}
I was messing around with this and was able to come up with something similar to what the question describes, the only difference being that you have to opt in to using it via a using namespace directive. (godbolt demo)
#include <iostream>
#include <vector>
#include <utility>
template <typename T>
// T can be a reference type
concept printable = requires(std::ostream& out, T t) {
out << std::forward<T>(t);
};
template <typename T>
requires (!printable<T>)
std::ostream& default_print(std::ostream& out, T&& t) {
return out << "DEFAULT";
}
namespace default_ostream
{
template<typename T>
std::ostream& operator<<(std::ostream& out, T&& t)
requires requires { default_print(out, std::forward<T>(t)); }
{
return default_print(out, std::forward<T>(t));
}
} // namespace default_ostream
int main()
{
using namespace default_ostream;
std::cout << std::vector{ 0, 1, 2 } << '\n';
std::cout << "Hello!\n";
std::cout << 2.234 << '\n';
}
This program will output the following with all of GCC, Clang and MSVC:
DEFAULT
Hello!
2.234
Putting the default operator<< in a seperate namespace and deferring the !printable<T> requirement to print_generic seems to work. With this you will have to do using namespace default_ostream; if you want this behaviour, which cannot appear at global scope, but is fine at function (or some namespace) scope.
This works because printable doesn't see the generic operator<< when it's used as a requirement to default_print, that way it can't get selected for out << std::forward<T>(t) in the requirement and avoids recursive instantiation.
When you want to use the generic operator<<, you have to bring it into the local scope with using namespace default_ostream;, so it participates in overload resolution and because of its requirement it will only get selected if there's no other operator<< available.
I ran into some trouble trying to inherit std::ostream and using a custom operator << which is basically doing some work and then forwarding to std::ostream <<, e.g.:
#include <iostream>
#include <ostream>
struct ostream : std::ostream{
using std::ostream::ostream;
template<typename T>
ostream &operator <<(T &&arg){
//some work...
static_cast<std::ostream&>(*this) << std::forward<T>(arg);
return *this;
}
};
int main(){
ostream cc(std::cout.rdbuf());
cc << "hello world";
//cc << "hello world" << std::endl; //couldn't deduce template parameter `T`
}
The problem is when using manipulators, like in the line I have commented out, gcc complains about [template argument deduction/substitution failed:].
Do I have to set the template type explicitly?, if so how?, because I cannot use the in class std::ostream::operator << due to incompleteness.
Live on Wandbox
Edit
I have just defined the custom operator << as a free function so not inside the class ostream
#include <iostream>
#include <ostream>
struct ostream : std::ostream{
using std::ostream::ostream;
};
template<typename T>
ostream &operator <<(ostream &os, T &&arg)
{
static_cast<std::ostream&>(os) << std::forward<T>(arg);
return os;
}
int main(){
ostream cc(std::cout.rdbuf());
cc << "hello world" << std::endl;
}
and it is working as expected, also for manipulators. Not sure why this makes a difference here, maybe someone could clarify this for me
The problem is that the manipulators are templated, and your class does not provide the information needed for selecting the right template parameters for std::endl. You should overload the operator<< for the manipulators:
struct ostream : std::ostream{
using std::ostream::ostream;
template<typename T>
ostream &operator <<(T &&arg){
//some work...
static_cast<std::ostream&>(*this) << std::forward<T>(arg);
return *this;
}
ostream &operator<<(
std::ostream &(*manip)(std::ostream&)) {
//some work...
static_cast<std::ostream&>(*this) <<manip;
return *this;
}
};
Note that the code in the question failed for the same reason that the following fails:
auto manip = std::endl;
It simply can't deduce the template parameters of endl.
Update
The alternative that makes the ovloading as a free function does not do what one may expect:
template<typename T>
ostream &operator <<(ostream &os, T &&arg)
{
static_cast<std::ostream&>(os) << std::forward<T>(arg);
return os;
}
int main(){
ostream cc(std::cout.rdbuf());
cc << "hello world" << std::endl;
}
The operator that gets std::endl is from the original iostream library. The compiler does not execute the overloaded function in this case, and that's why there is no compilation error.
If you don't want to overload the manipulators, you can provide the template parameters explicitly:
cc << "hello world" << std::endl<char, std::char_traits<char>>;
Consider the following code:
#include <iostream>
namespace ns1
{
struct A
{
};
template <class T>
std::ostream& operator << (std::ostream& os, const T& t)
{
return os << "ns1::print" << std::endl;
}
}
namespace ns2
{
template <class T>
std::ostream& operator << (std::ostream& os, const T& t)
{
return os << "ns2::print" << std::endl;
}
void f (const ns1::A& a)
{
std::cout << a;
}
}
int main()
{
ns1::A a;
ns2::f (a);
return 0;
}
Compilation fails with "ambiguous overload error" as per standard.
But why? Surely "equally good" operator in A's 'home' namespace should take precedence? Is there any logical reason not to do it?
If you want the overload in namespace A to be preferred than you'll have to add something to it to make it actually better. Say, by making it not a template:
namespace ns1
{
std::ostream& operator<<(std::ostream&, const A& );
}
Otherwise, there's really no conceptual reason to see why a function template in one namespace would be preferred to a function template in another namespace if both are exactly equivalent. After all, why would the function template in A's namespace be "better" than the function template in f's namespace? Wouldn't the implementer of f "know better"? Relying solely upon function signature sidesteps this issue.
If you carefully read the compiler-errors, the ambiguity error is not between the operator<< versions in ns1 and ns2, but between the operator<<(os, const char*) instantiation from ns1 and the exact same overload from namespace std. The latter is being dragged in by ADL on std::ostream.
The best approach is to use the recommendation by #Barry, and de-templatize the operator<< in namespace ns1, but also to add all functionality related to ns1::A (such as f(A)) into the same namespace:
#include <iostream>
namespace ns1
{
struct A {};
std::ostream& operator << (std::ostream& os, const A& t)
{
return os << "ns1::print" << std::endl;
}
void f (const A& a)
{
std::cout << a;
}
}
int main()
{
ns1::A a;
f(a); // rely on ADL to find ns1::operator<<(os, A)
}
Live Example
Namespace ns1 then acts as the broader interface of class A through ADL.
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;
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";
}