In the following example which overloads << operator:
#include <iostream>
template <typename T>
class MyClass {
public:
MyClass(T X, T Y):x(X), y(Y) {}
template <typename U>
friend std::ostream& operator <<(std::ostream &os, const MyClass<U> &cl);
private:
T x;
T y;
};
template <typename T>
std::ostream& operator <<(std::ostream &os, const MyClass<T> &cl)
{
os << cl.x << " " << cl.y;
return os;
}
int main()
{
MyClass<int> cl(1, 2);
std::cout << cl << std::endl;
}
I have searched other questions but I couldn't find why exactly do I need:
template <typename U>
friend std::ostream& operator <<(std::ostream &os, const MyClass<U> &cl);
the U instead of T in the typename? Because in the end U and T are both ints.
You can't use template <typename T> again because, on the rest of the line, it wouldn't know which of the two Ts you mean. It's kind of like this, which is also an error:
void foo(int x) {
int x = 4;
cout << x; // which x?
}
The compiler is not smart enough to figure out that in this case you will always want the two Ts to be the same, much like the error in the foo function above would not go away if you only ever called foo(4) in your program.
But what you've realized here is that you don't actually need the template arguments for operator<< at all here! That's because in this context you know exactly what type you want to use, whch is MyClass<T>. Normally, you can get rid of template parameters when you know the exact types you want. This is called an explicit specialization, and would normally look something like this:
template <>
friend std::ostream& operator<< <T>(std::ostream& os, const MyClass<T> &cl);
Note the empty template argument list template <>, which says "I don't need template arguments" and then the <T> after the function name, which says, "because I want the template argument type to be exactly T", where T is already known within a particular instantiation of the MyClass template. However this does not work here, because there is simply a rule in the C++ language specification that explicit specializations aren't allowed in friend declarations. (I am not exactly sure what the rationale is behind this rule, but it's a rule.)
So since you can't re-use the identifier T, and you can't explicitly specialize, the only option remaining is to use some other identifier, like U, for the template parameter.
Related
I am trying to understand how templates and friendship works in C++. So looking/trying out some examples by myself. One such example that i am unable to understand is given below:
VERSION 1
#include <iostream>
using namespace std;
//template<typename T> void func4();
//template<typename T> class NAME;
// template<typename T> std::ostream& operator<< (std::ostream&, NAME<T> const&);
template<typename T>
class NAME {
friend void func4<T>();
friend std::ostream& operator<< <T> (std::ostream&, NAME<T> const&);
};
int main()
{
cout << "Hello World" << endl;
return 0;
}
The above version 1 gives the following error:
prog.cc:13:17: error: variable or field 'func4' declared void
13 | friend void func4<T>();
| ^~~~~
prog.cc:13:17: error: expected ';' at end of member declaration
13 | friend void func4<T>();
| ^~~~~
| ;
prog.cc:13:22: error: expected unqualified-id before '<' token
13 | friend void func4<T>();
| ^
My first question is that even though i have commented the forward declarations for both func4 and operator<< template function, then how can i only get error only for func4? That is why is there no error for operator<<.
Note that i know we need forward declarations if we want to befriend a specific instantiation of a template. That is for
friend void func4<T>();
to work we need to comment out the statement
template<typename T> void func4();
and similarly for
friend std::ostream& operator<< <T> (std::ostream&, NAME<T> const&);
to work we need to comment out corresponding forward declaration at the starting of the program. But when i comment out only template<typename T> void func4(); statement, the program works and and there is no error for operator<<. Again why aren't we getting the error for operator<< even though i have not comment out the corresponding forward declarations.
My second question is that is the statement
friend void func4<T>();
same as
friend void func4<>();
Similarly, is the statement
friend std::ostream& operator<< <T> (std::ostream&, NAME<T> const&);
same as
friend std::ostream& operator<< <> (std::ostream&, NAME<T> const&);
My thinking is that the statement friend void func4<>(); is a specialization of the function template declared using the statement template <typename T> void func4();. Meanwhile when we write friend void func4<T>(); we are explicitly passing T so in this case when we write/call func4<int>(); the function template func4<int> will be intantiated and then occupy memory. On the other hand the specialised template function will already take up some memory since we have to provide its definition before we can call it. So can someone explain whether there is a difference when we use <T> and when we use <>. In summary, it seems to me that in case of <> a user supplied specialization will be used while in case of <T> a new intiantion will be created when we call func4(). So there is a difference because in case of <> we have to supply a definition which will already take some space(memory) while in the case of <T> func4 will only take space(memory) when we use/call it. Is this the correct conclusion?
My third question is that i have read that:
There is no way to explicitly specify template arguments to overloaded operators, conversion functions, and constructors, because they are called without the use of the function name.
According to the above quoted statement we cannot explicitly specify template arguments to overloaded operators, but then how can write friend std::ostream& operator<< <T> (std::ostream&, NAME<T> const&); as it overload operator << .
Answer 1
There is no error for operator<< because you have used using namespace std; and in the std namespace there is already overloaded operator<<.
Answer 3
The quoted statement talks about calling(i.e., using) overloaded operators not defining/declaring them
Answer 2
VERSION 1
#include <iostream>
template<typename T> void func4();
template<typename T>
class NAME {
//friend void func4<>();//this does not work because there is no way to deduce the template arguments
friend void func4<T>();//this works because here we have explicitly passed T as the template argument
};
int main()
{
std::cout << "Hello World" << std::endl;
NAME<int> n;
return 0;
}
In version 1 above we have a function template func4<>. Now when you write friend void func<T>(); and friend void func<>();, you are making the full specialization friend of the class template NAME<>. The reason friend void func<>(); does not work is that there is no way for template argument deduction to work in this case. While when you write friend void func<T>(); you have explicitly passed the template argument and so this works. This also means that both(friend void func<T> and friend void func<>();) are essentially the same specialization of the template function func<>. This will be more clear from my next example version 2.
VERSION 2
#include <iostream>
template<typename T> class NAME;
template<typename T> std::ostream& operator<<(std::ostream&, const NAME<T>& );
template<typename T>
class NAME {
//both of the below friend declarations are equivalent
friend std::ostream& operator<< <T>(std::ostream&, const NAME<T>&);//this works
friend std::ostream& operator<< <>(std::ostream&, const NAME<T>&);//this works as well becasue of template argument deduction
};
int main()
{
std::cout << "Hello World" << std::endl;
NAME<int> n;
return 0;
}
In version 2 above we have an overloaded operator function template. Both friend std::ostream& operator<< <T>(std::ostream&, const NAME<T>&); and friend std::ostream& operator<< <>(std::ostream&, const NAME<T>&); are equivalent and are the same specialization of the overloaded template operator<< <T>. The only difference between them is that the second one uses template argument deduction. This is possible because unlike version 1, we have a function argument that depends on T this time so template argument deduction can work. This was not possible in case of function template func4<> because that function does not take any parameter that depends on the template parameter.
I have a template class that defines some member types. It's similar to how std::map defines it's value_type based on it's own template arguments, but in my case the type is more complex, so it's defined as nested class.
Now for debugging I would like to define operator<< for that type. But the compiler tells me it can't deduce the template parameters of the outer template.
My real code is not contrived like the following example, but this contrived example demonstrates the approach I tried and how it fails:
#include <iostream>
template <typename Value> class Outer;
template <typename Value>
std::ostream &operator<<(std::ostream &, const typename Outer<Value>::Inner &);
template <typename Value>
class Outer {
public:
struct Inner {
Value x;
};
void PrintSomething(Value v) {
// the real program does something useful with the inner class, of course
Inner inner = { v };
std::cout << "Inner = " << inner << std::endl; // <---- THIS SAYS IT CAN'T FIND operator<<
};
};
template <typename Value>
std::ostream &operator<<(std::ostream &s, const typename Outer<Value>::Inner &v) {
return s << v.x;
}
int main() {
Outer<int> o;
o.PrintSomething(42);
return 0;
}
This is complete sample to reproduce the problem. The compiler (I've tried 3 of them) says there is no overload of operator<< that would take second argument of type Outer<int>::Inner. When I try the same thing with different function that does not have other overloads, it instead says C2783: could not deduce template argument for 'identifier', gcc and clang keep saying there is no overload that takes second argument Outer<int>::Inner).
So is there a way to define operator<< taking Outer<Value>::Inner for any Value as it's right (so it can't be defined as member) argument?
Note: I need it to compile in several compilers and some of them don't have any C++11 features, so I need it to be C++03.
What you have there is a so-called non-deducible context. How could Value ever be deduced? You can partially specialize class templates, making it practically impossible for the compiler to even try and test every possible instantiation (of which there are.. well, infinite).
There are two workarounds: Take Inner out of Outer, or make operator<< an inline friend. The latter is the usual way people go.
template<class T>
struct Outer{
struct Inner{
T value;
friend std::ostream& operator<<(std::ostream& os, Inner const& v){
return os << v.value:
}
};
// ...
};
The following code works, but i would like to move ostream& operator<< outside of the class declearation as i have with hash::operator[].
#include<iostream>
#include<map>
using namespace std;
template <class T>
class hash {
private:
map<string, T> _map;
public:
T& operator[] (string x);
friend ostream& operator<<(ostream& out, const hash<T> &rhs) { return out << "test"; }
};
template <class T>
T & hash<T>::operator[](string x) {
return _map[x];
}
int main () {
hash<int> myobject;
myobject["a"] = 1;
cout << myobject["a"] << endl;
cout << myobject << endl;
return 0;
}
I have tried:
template <class T>
ostream& operator<<(...) {
return out << "test";
}
and
ostream& operator<<(...) {
return out << "test";
}
as well as a few other combinations to no avail.
Since it does not seem that this question is getting closed as exact duplicate, I will explain what your program does.
template <typename T>
class test {
int private_field;
friend std::ostream& operator<<( std::ostream&, test<T> const & );
};
// ???
int main() {
std::cout << test<int>() << std::endl;
}
Templates are instantiated on demand (unless you explicitly instantiate them), that means that in this particular program test is instantiated only as test<int>. When the compiler instantiates the template (because it was requested in main) it will process the template definition. At this point the behavior is similar to rewriting the code with the substituted type at the point of definition (in this case right before main):
class test<int> {
friend std::ostream& operator<<( std::ostream&, test<int> const & );
};
Now, if you look at the instantiated template, you can note that the friend declaration is befriending a non templated function. So in this particular program you can fill in the ??? with that particular function:
std::ostream& operator<<( std::ostream& o, test<int> const & t ) {
return o << t.private_field;
}
The problem here is that this is not easily extensible. The code of that operator<< is the same for test<int> than it is for test<double>, so there should be no need to rewrite the same function for all instantiating types!
At this point there are two options, the first one is, as you have already identified, providing the definition of the function inside the class. The compiler will then process and define the function whenever the type is being instantiated. This solution creates non-templated functions on demand for each template instantiation (which is the option I would do, even with the quirks and strangeness of lookup here).
Now, if you really want to avoid providing the definition inside the templates class, and you still want to provide a single implementation, then you have to resort to providing a templates operator<<. At this point you have two different options, you can declare all instantiations of the template (which I don't quite like, as it opens to too many others), or you can befriend a single specialization of the template function (cleaner regarding access, more cumbersome to write).
The first case is:
template <typename T>
class test {
template <typename U>
friend std::ostream& operator<<( std::ostream&, test<U> const & );
};
template <typename T>
std::ostream& operator<<( std::ostream&, test<T> const & ) { ... }
The second case requires a couple of forward declarations:
template <typename T> test;
template <typename T> std::ostream& operator<<( std::ostream&, test<T> const & );
template <typename T>
class test {
friend std::ostream& operator<< <T>( std::ostream&, const test<T>& );
};
template <typename T>
std::ostream& operator<<( std::ostream&, test<T> const & ) { ... }
There is of course another option: do not declare friends at all. Provide a print(std::ostream&) public function in your class that has the implementation, and provide a non-templated operator<< that just calls print on the second argument.
You have to be careful when you use friend and template
#include<iostream>
#include<map>
template <class T>
class MyHash{
public:
// ... use your T template here
template <class U>
friend ostream& operator<<(ostream& out, const MyHash<U> &rhs);
};
// ...
template <class U>
ostream& operator<<(ostream& out, const MyHash<U> &rhs){ return out << "test"; }
you need to use a different template U because operator<< is a friend method (external), if we use T instead of U, we will have : ambiguous definition in template .
Change hash by MyHash to avoid ambiguities.
Edit :
The error that you get here is :
error C2676: '<' binaire : 'std::string' ne définit pas cet opérateur
ou une conversion vers un type acceptable pour l'opérateur prédéfini
because you forgot to include <string> in "hash.h". That header defines the < operator.
And also try moving the definition of operator[] and operator<< directly into "hash.h"
Both the declaration and definition of templates must be included. This is because in some compilers template functions cannot be compiled and linked independently, since they are generated on request for the specific types they are instantiated with.
Change the #include "hash.cpp" to #include "hash.h"
While reading from Thinking in C++ Volume 2, from the Templates in Depth chapter, I see that if you have a friendly function in a template class, you need to forward declaration that function. I made this example to test this, overlaoding the output operator:
#include <iostream>
using namespace std;
/*
template<class T>
class X;
template<class T>
ostream& operator << (ostream& os, const X<T>& x);
*/
template<class T>
class X {
T t;
public:
X(T i): t(i) {}
friend ostream& operator << (ostream& os, const X<T>& x)
{
return os << x.t;
}
};
int main()
{
X<int> a(1);
cout << a;
return 0;
}
But it works without the forward declaration, but then I test it with the definition of << outside of the class:
friend ostream& operator << <>(ostream& os, const X<T>& x); (inside of the class)
template<class T>
ostream& operator << (ostream& os, const X<T>& x)
{
return os << x.t;
}
I am not sure why with the definition inside of the class it doesnt apply, is it because you have to explicit say that the ostream operator function is a template ? (using <> ) ??
Sorry for the confusion.
Since it seems that my comment was satisfactory, here it is in form of an answer.
The C++FAQ Lite has a chapter on this, which, for the sake of completeness, boils down to two possible ways to convince the compiler while it is examining the body of the class X that the friend function operator<< is actually a function template.
One approach is, as you did, declare the function template operator<< before the class definition and use the <> in the friend line inside the class body, giving the remarkable syntax of operator << <>(.
The other approach is to define the entire body of the friend template function inside the body of class X, which makes the forward declaration unnecessary.
How can I make the insertion (<<) and/or extraction (>>) operator overloaded in a template class WITHOUT making it inline. I would like to have the << or >> operator as a friend class.
I know how to make it inline
example of inline in a matrix class
friend ostream& operator<<(ostream& ostr, const Matrix<T>& inputMatrix)
{
...
// create the ostr
return ostr;
}
but I'd like to have the code outside of the templateclass definition.
g++ told me to add <> after the function name so I did but when I tried to instansiate a matrix of type SOMETYPE it gave me an error that it didn't know how to extract or insert for that type.
If you really want to define the operator externally and befriend only the operator instantiation that coincides in type with this template instantiation, the correct syntax is:
template <typename T> class test; // forward declare template class
template <typename T> // forward declare the templated operator
std::ostream& operator<<( std::ostream&, test<T> const & );
template <typename T>
class test { // define the template
friend std::ostream& operator<< <T>( std::ostream&, test<T> const & ); // befriend
};
template <typename T> // define the operator
std::ostream& operator<<( std::ostream& o, test<T> const & ) {
return o;
}
In most cases it is not worth the hassle to pull the definition out of the class, considering that you still need to provide it in a header and the extra work required.
Also note that there are slight differences for the compiler regarding lookup. In the case where the function is inlined inside the class definition, the compiler will not find that function unless one of the arguments is actually of the type of the template, so it effectively reduces the visibility and the amount of work that the compiler has to do (if the templated operator<< is defined outside of the class, the compiler will find it as a candidate for overload resolution in all places where it finds a << b, only to discard it in all cases where the second argument is not a test<T> (and it will show the templated operator as a candidate in all error messages where it cannot match operator<<, which is a long enough list already).
Try something like:
template <typename T> class Matrix;
template <typename T> std::ostream& operator<<(std::ostream& ostr, const Matrix<T>& m);
template <Typename T>
class Matrix
{
public:
friend ostream& operator<< <T> (ostream& ostr, const Matrix<K>& inputMatrix);
};
// This must be in the same translation unit as the class definition!
template<typename T>
ostream& operator<<(ostream& ostr, const Matrix<T>& inputMatrix)
{
// ...
return ostr;
}
Translation unit reference
re-re-edited to addressed the comments made by aschepler and dribeas.
Place the code in the header, outside the class definition. Or, place it in a .tcc file and include it at the bottom of the header.