Behavior of C++ templates and operator overloading - c++

I would like to understand the following code behavior
#define USE_FRIEND
class Foo
{
public:
template <typename T>
Foo& operator<< (T val)
{
std::cout << "Inside Foo" << std::endl;
return *this;
}
};
class A
{
public:
#ifdef USE_FRIEND
friend Foo& operator<<(Foo& f, A& a)
{
std::cout << "Inside A" << std::endl;
return f;
}
#endif
};
int main()
{
A a;
Foo f;
#ifdef USE_FRIEND
std::cout << " using Friend :: ";
#else
std::cout << " not using Friend :: ";
#endif
f << a;
system("pause");
return 0;
}
The output for the above code for 2 executions, one with Using friend and another without:
case 1:
using Friend :: Inside A
case 2:
not using Friend :: Inside Foo
I can understand case 2, but can anyone explain case 1

Overload resolution is complicated business, but here are the two rules that are relevant:
The overloads that are viable are:
template <typename T> Foo & Foo::operator<<(T)
Foo & operator<<(Foo &, A &)
When you call operator<<(f, a), then both overloads match, and they both match on the nose, deducing T = A in the template. There is no difference in exactness, since a reference counts as a "perfect match".
Thus the two overloads are tied, and the resolution would appear to be ambiguous. However, there is a tie breaker: No 1 is a template and No 2 is not. In this case, the non-template is a better match.

Related

streaming operator overloading for nested type names inside templates

The following code does not compile:
#include <type_traits>
#include <optional>
#include <iostream>
using namespace std;
namespace dbj {
template< typename K, typename V >
class top final {
static_assert(
! is_same_v<K,V>,
" to make things simpler K and V must be different types"
);
public:
// nested type names
using key_type = optional<K>;
using val_type = optional<V>;
using type = top;
private:
key_type key_{};
val_type val_{};
public:
top() = delete;
explicit top(K k, V v) : key_(k), val_(v) {}
private:
// PROBLEM A: not found by
// friend wostream & operator << (wostream & os, type top_)
friend wostream & operator << (wostream & os, key_type key_arg_ ) {
return os << L"\nK : " << key_arg_.value_or(K{});
}
// PROBLEM B: not found by
// friend wostream & operator << (wostream & os, type top_)
friend wostream & operator << ( wostream & os, val_type val_arg_ ) {
return os << L"\nV : " << val_arg_.value_or(V{});
}
// found no problem
friend wostream & operator << (wostream & os, type top_)
{
// ISSUE D: this is not looking for overloads in the immediate scope
// i.e. inside the template class
// this is first looking for operator declaration inside namespace dbj
return os << L"\n\nprinting dbj::top<K,V> : " << top_.key_ << L"," << top_.val_;
}
}; // top
} // dbj ns
using top_type = dbj::top<wstring, int>;
extern "C" int test_operator_overloading_puzzle()
{
top_type top_{ L"the key", 42 };
std::wcout << top_ << std::endl;
return 1;
}
Also available here: https://wandbox.org/permlink/jMKpn6CKFL2cyceO
Every compiler complains that within the streaming operator for type top_, no match is found for streaming top_.key (marked ISSUE D in the code above). Why can't lookup find the two streaming functions I declared directly above them?
Here's a simpler reproduction:
namespace A {
struct X { };
}
namespace B {
struct Y {
A::X x;
// #1
friend std::ostream& operator<<(std::ostream& os, A::X) {
return os;
}
// #2
friend std::ostream& operator<<(std::ostream& os, Y y) {
return os << y.x; // error: no match for operator<<
}
};
}
This is because of how name lookup works. When you declare and define a namespace-scope friend function like this, that function can only be found by argument-dependent lookup of its arguments. It is never found by regular unqualified lookup.
But the function you're declaring in #1 isn't actually in the associated namespace of any of its arguments - the function is declared in namespace B, but its two arguments are in namespace std and namespace A, respectively. As a result, when we write os << y.x, no matching candidates are found by regular unqualified lookup and then no candidates are found by argument-dependent lookup either - #1 is not in the right namespace. Hence, no candidates.
The shortest solution is to just add a namespace-scope declaration of #1 outside of struct Y:
namespace B {
std::ostream& operator<<(std::ostream&, A::X);
struct Y { ... };
}
Now, this function can be found by regular unqualified lookup, so the call in #2 works. But really, there's no reason to have declared #1 as a friend function with B::Y (it in no way refers to B::Y), so just declare it externally. It also doesn't work very well as a streaming operator, so probably just make it a regular function instead.
Just building on top of Barry's simplification of the question and then on top of his answer.
namespace {
using namespace std;
namespace A {
struct X {
// #1 --> SOLUTION to problem #1
// friend operator is here in the scope where
// name lookup can find it, declared and defined
friend wostream& operator<<(wostream& os, X) {
return os << L"A::X" ;
}
};
}
namespace B {
struct Y {
A::X x;
// #1 --> PROBLEM: name lookup can not find this
// as it is in the scope unrelated to A::X
/*
friend std::ostream& operator<<(std::ostream& os, A::X) {
return os;
}
*/
// #2
friend wostream& operator<<(wostream& os, Y y) {
// << y.x is normally found inside the
// type of x and that is A::X
return os << L"\nB::Y --> " << y.x;
}
};
}
void test_barry() {
B::Y by_;
wcout << by_;
}
}
This is for the situations when we can insert the necessary friend operator inside the nested type. Otherwise please see Barry's answer.
For further education opportunity perhaps this is a good start.

How to properly define and call original operator<<

Consider the following example:
#include <iostream>
class A {
const int i;
const int j;
public:
A(int i_, int j_) : i(i_), j(j_) {}
std::ostream& operator<<(std::ostream& o) const {
o << "i is " << i << ", j is " << j;
return o;
}
};
std::ostream& operator<<(std::ostream& o, const A& a ) {
o << "This is A: ";
a.operator<<(o);
return o;
}
int main() {
A a(0,42);
std::cout << a << std::endl;
return 0;
}
It will generate the following output:
This is A: i is 0, j is 42
The output is correct but I don't like how I am calling A's original operator<<.
I am trying to figure out how to properly define that operator, so it could be called this way:
o << "This is A: " << (some magic)a;
instead of
o << "This is A: ";
a.operator<<(o);
I have tried various ways but either I get to ambiguity issues or getting an address of the std::cout and broken string. Notice that the result std::ostream& of A::operator<< is a remnant of my tests. In the example above it would suffice to use void.
Is it possible without creating an intermediate class B that derives from class A and defines its own operator<< (class NiceOutputOfA : public A {...};) ?
Binary operators defined in-class always have the class as the left-hand side operand. Which means you cannot implement stream insertion/extraction in-class.
Probably the most common way is to implement the operator as a friend defined inline in the class.
Another reasonably common way is to provide a named streaming function in the class, and an out-of-class streaming operator which calls that function. You almost did that, but named that function operator <<.
The closest resolution I came to is by creating an intermediate class:
class Decorate {
const A& a;
public:
Decorate(const A& a_) : a(a_) {}
friend std::ostream& operator<<(std::ostream& o, const PrintA& pa) {
o << "This is A: " << pa.a;
return o;
}
};
and having it printed this way:
int main() {
A a(0,42);
std::cout << Decorate(a) << std::endl;
return 0;
}
I was looking for something prettier but based on Angew's answer I lost hope to have it done suing proper operator<< declaration.
Thanks for all your help!
Marking Angew's response as the answer.

explicit specialization for overloading operator '<<' (left shift)

Lets say i have a class, for which i want to overload an operator based on an enum type:
#include <iostream>
enum class option : char { normal, do_something_stupid };
class foo
{
public:
int i;
explicit foo(int a=0) : i(a) {};
/* overload operator '+=' based on 'option' */
template<option E = option::normal>
void operator+=(const foo& f) { i += f.i; }
};
/* explicit specialization for operator += */
template<> void foo::operator+=<option::do_something_stupid>(const foo& f)
{ i += (f.i +1000); }
int main()
{
foo f1(1), f2(2);
f1 += f2;
std::cout << "\nf1 = " << f1.i;
f1.operator+=<option::do_something_stupid>(f2);
std::cout << "\nf1 = " << f1.i;
std::cout << "\n";
return 0;
}
This builds clean (ignoring the fact that it really does something pretty dump) both on g++ and clang++.
What if i want to overload the '<<' operator the same way? A similar approach does not seem to work:
#include <ostream>
#include <iostream>
enum class option : char { normal, do_something_stupid };
class foo
{
public:
int i;
explicit foo(int a=0) : i(a) {};
template<option E = option::normal>
friend std::ostream& operator<<(std::ostream& o, const foo& f)
{ o << f.i; return o; }
};
template<> std::ostream&
operator<< <option::do_something_stupid>(std::ostream& o, const foo& f)
{
o << f.i + 1000;
return o;
}
int main()
{
foo f1(1), f2(2);
std::cout << "\nf1= " << f1;
std::cout << "\nf2= ";
/* this triggers an error with g++ */
std::cout.operator<< <option::do_something_stupid>(f1);
std::cout << "\n";
return 0;
}
According to g++, the call from main to the operator is invalid:
error: no match for ‘operator<’ (operand types are ‘<unresolved overloaded function type>’ and ‘option’)
std::cout.operator<< <option::do_something_stupid>(f1);
clang++ on the other hand, produces a different error message:
lsfov.cc:20:1: error: 'operator<<' cannot be the name of a variable or data member
operator<< <option::do_something_stupid>(std::ostream& o, const foo& f)
^
lsfov.cc:20:11: error: expected ';' at end of declaration
operator<< <option::do_something_stupid>(std::ostream& o, const foo& f)
^
;
lsfov.cc:20:12: error: expected unqualified-id
operator<< <option::do_something_stupid>(std::ostream& o, const foo& f)
^
lsfov.cc:33:15: error: reference to non-static member function must be called
std::cout.operator<< <option::do_something_stupid>(f1);
~~~~~~~~~~^~~~~~~~~~
which goes on listing possible overload of '<<' from the standard library (if i understand correctly), like:
/usr/bin/../lib/gcc/x86_64-redhat-linux/5.3.1/../../../../include/c++/5.3.1/ostream:108:7: note: possible target for call
operator<<(__ostream_type& (*__pf)(__ostream_type&))
^
/usr/bin/../lib/gcc/x86_64-redhat-linux/5.3.1/../../../../include/c++/5.3.1/ostream:117:7: note: possible target for call
operator<<(__ios_type& (*__pf)(__ios_type&))
^
What is going on? Is this kind of operator specialization possible/allowed? If so, what is the proper way to call the operator? Or is clang correct and the definition is ill formed?
I think clang doesn't like the declaration of the friend in relation to the specialisation. Re-ordering them does the trick.
enum class option : char { normal, do_something_stupid };
// forward declare the class and operator
class foo;
template<option E = option::normal>
std::ostream& operator<<(std::ostream& o, const foo& f);
// the class with the declared friend operator
class foo
{
private:
int i;
public:
explicit foo(int a=0) : i(a) {};
template<option E>
friend std::ostream& operator<<(std::ostream& o, const foo& f);
};
// the operator implementations
template<option E>
std::ostream& operator<<(std::ostream& o, const foo& f)
{ o << f.i; return o; }
template<> std::ostream&
operator<< <option::do_something_stupid>(std::ostream& o, const foo& f)
{
o << f.i + 1000;
return o;
}
In addition, the operator<< used in the main is not a member cout, but rather a global.
int main()
{
foo f1(1), f2(2);
std::cout << "\nf1= " << f1;
std::cout << "\nf2= ";
/* this triggers an error with g++ */
operator<< <option::do_something_stupid>(std::cout, f1);
std::cout << "\n";
return 0;
}
Sample here. g++ is also happy with the code as above.
A note on operators in a non-deduced context. I assume you are using the code here in a greater project of some sort, but if the operator is being used with non-deduced parameters, it is often easier and clearer to implement the functionality in a member method or a free function (using friend as required).

Why I cannot put this operator overload in the same namespace as the struct?

I have the following code:
#include <iostream>
#include <vector>
namespace X {
std::ostream& operator<<(std::ostream& os,const std::vector<double>& v){
for (int i=0;i<v.size();i++){os << v[i] << " ";}
return os;
}
namespace Y {
struct A {std::vector<double> x;};
std::ostream& operator<<(std::ostream& os,const A& a){
os << a.x << std::endl;
return os;
}
}
}
using namespace X;
int main(int argc, char** argv) {
std::vector<double> v(10,0);
std::cout << v << std::endl;
Y::A a;
std::cout << a << std::endl;
return 0;
}
The first overload works, but the second one does not. For some reason it cannot find the first one. I get the error:
no match for 'operator<<' (operand types are 'std::ostream
{aka std::basic_ostream<char>}' and 'const std::vector<double>')
os << a.x << std::endl;
^
I do not understand why I get this error. For example something like this seems to be completely valid:
namespace A {
void foo(){}
namespace B {
void bar(){foo();}
}
}
However, the only way to fix the above problem was to put the second overload also in X. Why is it not possible to have it in the same namespace as the struct (ie. X::Y)?
PS: I was reading on ADL and I found some related questions (e.g. this and this, but what I understood from reading this, the above should work.
In Argument Depended Lookup (or Koenig Lookup), compiler adds to the scope of visibility all symbols declared in parent scopes of each parameter.
Even if Y is "child namespace" of X, they are not related in terms of ADL. First of your parameters is type defined in std:: namespace, while second is local symbol (defined in the same namespace as the function itself).
Note, that because of reasons mentioned above, you will most likely get another error in this line:
std::cout << v << std::endl;
when compiler will not be able to find operator<< overloaded for std::vector<double> (because it lies inside namespace X).
To solve this, you can use:
using X::operator<<
inside namespace Y or move that overload.
If you are wondering, why foobar example works: that's because ADL (Argument Dependent Lookup) is about scope of parameters of functions, not functions themselves. In foobar code, ADL isn't applied.
As per other answers, I eventually deduced that ADL of operator<< was being impeded by the fact that it was taking place inside another operator<<.
Today's lesson: always write an operator<< overload in terms of a writer method :)
Here's the fix:
#include <iostream>
#include <vector>
namespace X
{
std::ostream& operator<<(std::ostream& os,const std::vector<double>& v){
for (int i=0;i<v.size();i++){os << v[i] << " ";}
return os;
}
namespace Y
{
struct A
{
std::vector<double> x;
void write(std::ostream&os) const {
os << x << std::endl;
}
};
std::ostream& operator<<(std::ostream& os,const A& a)
{
a.write(os);
return os;
}
}
}
using namespace X;
int main(int argc, char** argv)
{
std::vector<double> v(10,0);
std::cout << v << std::endl;
X::Y::A a;
std::cout << a << std::endl;
return 0;
}
As simple as this: In order to overload a function the overloaded version have to lives in the same nemaspace, otherwise, is a completely different function. The name of the function (for the compiler) is the complete path from the global namespace to the function itself.
::function_at_global_namespace();
Namespace::function_name(); // Some funtion within a namespace;
Namespace_1::function_name(); // Some other function within another namespace;
So,
Standar std::ostream& operator<< lives in std namespace, you are not overloading that operator, Just defining anotherone in namespace X.
As pointed by #0x499602D2 you must use X::operator<< in namespace Y in order to call that version of the operator.
std::ostream& std::operator<< and std::ostream& X::operator<< are diferent functions.
In following code none of the foo versions are overloading either.
// What version of foo gets called? A::foo, or B::foo?
namespace A {
void foo(){cout << "A::foo" << endl;}
namespace B {
void foo(){ cout << "B::foo" << endl;}
void bar(){foo();}
}
}
namespace C { void foo(int a) { cout << "C:foo" << endl; } }

how to template for operator<< for ostream

The following won't compile for me. I'm out of ideas... Any help?
template<>
inline
std::ostream& operator<< <const std::map<std::string, std::string> > (std::ostream& stream, const std::map<std::string, std::string>& some_map)
{
return stream;
}
g++ gives me the following error:
error: expected initializer before '<' token
Edit: 1
Okay, since everyone is telling me to overload, let me give you an example that wouldn't make sense for overloading. What if I have this:
template <typename T>
inline
std::ostream& operator<<(std::ostream& stream, const T& something)
{
stream << something.toString();
return stream;
}
class Foo
{
public:
Foo(std::string s)
{
name = s;
}
std::string toString() const
{
return name;
}
private:
std::string name;
};
class Bar
{
public:
Bar(int i)
{
val = i;
}
std::string toString() const
{
std::ostringstream stream;
stream << val;
return stream.str();
}
private:
int val;
};
int main(int, char**)
{
Foo foo("hey");
Bar bar(2);
std::cout << foo << std::endl;
std::cout << bar << std::endl;
return 0;
}
Now this won't work either.
I just want to avoid having to overload operator<< over and over by using a template like above. This seems like it should be possible. I would like to know if it is, and if so, how?
In such a scenario, overloading for both Foo and Bar to do the same thing would be a waste, that is why I am trying to avoid it.
Edit: 2
Okay, it appears that I am being misunderstood. Here is another attempt to clarify:
template <typename T>
std::ostream& operator<<(ostream& stream, const T& t)
{
for(typename T::const_iterator i = t.begin(), end = t.end(); i != end; ++i)
{
stream << *i;
}
return stream;
}
int main(int, char**)
{
set<int> foo;
list<string> bar;
vector<double> baz;
cout << foo << " " bar << " " << baz << endl;
};
The above code won't work mind you. Complains about ambiguity. But it seems like the better solution for printing out containers. If I did it the with overloading, I would need to write a version of operator<< for each container/datatype combination, which would yield a ridiculous amount of code duplication.
This doesn't need to be a template function.
std::ostream & operator<<(std::ostream & stream, const std::map<std::string, std::string> & some_map)
{
return stream;
}
Edit:
In reference to my comment about writing Java in C++(and sorry if it sounded rude, I didn't intend to be smarmy). Tell me if this doesn't work better for you. Instead of writing a "toString" method in the first place, just overload the operator<< to begin with. The function is nearly identical. Then, you can write a non-member template toString function that will automatically work with all of your classes, like this:
#include <sstream>
#include <string>
template<typename T>
std::string toString(const T & val)
{
std::ostringstream ostr;
ostr << val;
return ostr.str();
}
Edit 2
Here's my alternative if you still insist on doing it your way. Make all of your classes with the toString method inherit from an abstract class with a virtual toString method, then write one operator<< to handle all of them.
class Stringifiable
{
public:
virtual std::string toString() const = 0;
};
std::ostream & operator<<(std::ostream & ostr, const Stringifiable& something)
{
return ostr << something.toString();
}
Now the compiler will choose your overload over templates.
You can use SFINAE to remove the template overload from consideration. Note that this has to be a part of the signature of the function. Thus you can use boost::enable_if:
template < typename T >
typename boost::enable_if< meta_function_to_check_for_concept<T>, std::ostream&>::type
operator << (std::ostream & out, T const& t)
{
...
}
If you don't do this then your template will attempt to match almost anything and will explode for every use of << that is not in line with the concept you're trying to match.
Your example is a bit contrived and might not lend itself to this answer, but there are situations in which it's warranted. This is how to do it.
In Crazy Eddie's answer, he mentions SFINAE. Now, C++11 has that built in. If all types derive from the same base class, this is made pretty simple. Here's a more complete example using C++11:
#include <type_traits>
#include <iostream>
#include <ostream>
class MyBaseType {};
class MyClass : MyBaseType {};
class MyOtherClass : MyBaseType {};
class SomeType {};
template <typename T>
typename std::enable_if<std::is_base_of<MyBaseType,T>::value,std::ostream&>::type
operator<<(std::ostream& out, const T& x)
{
out << 1;
}
int main()
{
MyBaseType x;
MyClass y;
MyOtherClass z;
SomeType i;
std::cout << x << y << z; // success!
std::cout << i; // compile-time failure!
}