Overloading Friend Operator≪≪ For Template Class

C++ template friend operator overloading

It's just a warning about a tricky aspect of the language. When you declare a friend function, it is not a member of the class the declaration is in. You can define it there for convenience, but it actually belongs to the namespace.

Declaring a friend function which is not a template, inside a class template, still declares a non-template function in the namespace. It is neither a member of the class, nor itself a template. However, it is generated by the class template.

Generating non-template functions from a template is a bit hazy. For example, you cannot add a declaration for that function outside the class block. Therefore you must define it inside the class block as well, which makes sense because the class template will generate it.

Another tricky thing about friends is that the declaration inside class Float {} does not declare the function in the namespace. You can only find it through argument-dependent meaning overload resolution, i.e. specifying an that an argument has type Float (or a reference or pointer). This is not an issue for operator+, as it is likely to be overloaded anyway, and it will never be called except for with user-defined types.

For an example of a potential issue, imagine you have a conversion constructor Float::Float( Bignum const& ). But Bignum does not have operator+. (Sorry, contrived example.) You want to rely on operator+(Float const&, Float const&) for Bignum addition. Now my_bignum + 3 will not compile because neither operand is a Float so it cannot find the friend function.

Probably, you have nothing to worry about, as long as the function in question is an operator.

Or, you can change the friend to be a template as well. In that case, it must be defined outside the class {} block, and declared before it, instead of needing to be declared and defined inside.

template<int E, int F> // now this is a template!
Float<E, F> operator+ (const Float<E, F> &lhs, const Float<E, F> &rhs);

template<int E, int F>
class Float
{
// deduce arguments E and F - this names operator+< E, F >.
friend Float<E, F> operator+<> (const Float<E, F> &lhs, const Float<E, F> &rhs);
};

C++ Template Inner Class Friend Operator Overload

The issue with the code in the question ended up being that template deduction is not attempted on type names nested inside a dependent type (e.g. Outer<Type>::Inner).

This question is essentially a duplicate of Nested template and parameter deducing. A detailed explanation on why this is a problem can be found here.

overloading friend operator for template class

This is one of those frequently asked questions that have different approaches that are similar but not really the same. The three approaches differ in who you are declaring to be a friend of your function --and then on how you implement it.

The extrovert

Declare all instantiations of the template as friends. This is what you have accepted as answer, and also what most of the other answers propose. In this approach you are needlessly opening your particular instantiation D<T> by declaring friends all operator<< instantiations. That is, std::ostream& operator<<( std::ostream &, const D<int>& ) has access to all internals of D<double>.

template <typename T>
class Test {
template <typename U> // all instantiations of this template are my friends
friend std::ostream& operator<<( std::ostream&, const Test<U>& );
};
template <typename T>
std::ostream& operator<<( std::ostream& o, const Test<T>& ) {
// Can access all Test<int>, Test<double>... regardless of what T is
}

The introverts

Only declare a particular instantiation of the insertion operator as a friend. D<int> may like the insertion operator when applied to itself, but it does not want anything to do with std::ostream& operator<<( std::ostream&, const D<double>& ).

This can be done in two ways, the simple way being as @Emery Berger proposed, which is inlining the operator --which is also a good idea for other reasons:

template <typename T>
class Test {
friend std::ostream& operator<<( std::ostream& o, const Test& t ) {
// can access the enclosing Test. If T is int, it cannot access Test<double>
}
};

In this first version, you are not creating a templated operator<<, but rather a non-templated function for each instantiation of the Test template. Again, the difference is subtle but this is basically equivalent to manually adding: std::ostream& operator<<( std::ostream&, const Test<int>& ) when you instantiate Test<int>, and another similar overload when you instantiate Test with double, or with any other type.

The third version is more cumbersome. Without inlining the code, and with the use of a template, you can declare a single instantiation of the template a friend of your class, without opening yourself to all other instantiations:

// Forward declare both templates:
template <typename T> class Test;
template <typename T> std::ostream& operator<<( std::ostream&, const Test<T>& );

// Declare the actual templates:
template <typename T>
class Test {
friend std::ostream& operator<< <T>( std::ostream&, const Test<T>& );
};
// Implement the operator
template <typename T>
std::ostream& operator<<( std::ostream& o, const Test<T>& t ) {
// Can only access Test<T> for the same T as is instantiating, that is:
// if T is int, this template cannot access Test<double>, Test<char> ...
}

Taking advantage of the extrovert

The subtle difference between this third option and the first is in how much you are opening to other classes. An example of abuse in the extrovert version would be someone that wants to get access into your internals and does this:

namespace hacker {
struct unique {}; // Create a new unique type to avoid breaking ODR
template <>
std::ostream& operator<< <unique>( std::ostream&, const Test<unique>& )
{
// if Test<T> is an extrovert, I can access and modify *any* Test<T>!!!
// if Test<T> is an introvert, then I can only mess up with Test<unique>
// which is just not so much fun...
}
}

Overloading friend operator for template class [duplicate]

You declare operator<< as returning an ostream&, but there is no return statement at all in the method. Should be:

template <class T, class U>
ostream& operator<<(ostream& out, Pair<T,U>& v)
{
return out << v.val1 << " " << v.val2;
}

Other than that, I have no problems or warnings compiling your code under Visual Studio 2008 with warnings at level 4. Oh, there are the classical linker errors, but that is easily bypassed by moving the template function definition to the class declaration, as explained in the C++ FAQ.

My test code:

#include <iostream>
using namespace std;

template <class T, class U>
class Pair{
public:
Pair(T v1, U v2) : val1(v1), val2(v2){}
~Pair(){}
Pair& operator=(const Pair&);
friend ostream& operator<<(ostream& out, Pair<T,U>& v)
{
return out << v.val1 << " " << v.val2;
}
private:
T val1;
U val2;
};

int main() {
Pair<int, int> a(3, 4);
cout << a;
}

how to overload operator == outside template class using friend function?

@Kühl's answer is the most permissive approach to declare a templated friend function of a templated class. However, there is one unapparent side effect of this approach: All template instantiations of Point are friends with all template instantiations of operator==(). An alternative is to make only the instantiation with the same type of Point a friend. Which is done by adding a <T> in the friend declaration of operator==().

template <typename T> class Point;

template <typename S>
bool operator== (Point<S>, Point<S>);

template <typename T>
class Point {
// ...
friend bool operator==<T> (Point, Point);
};

References

http://web.mst.edu/~nmjxv3/articles/templates.html

C++ template class friend operator overloading

Try this function signature instead (not tested):

template <typename T, typename F>
Vector<T> operator*(const F &lhs, const Vector<T>& rhs);

It should allow for statements like:

auto vec = f * other_vec;

for any type F which has a defined operator of the kind:

template <typename F, typename T>
undetermined operator*(const F& lhs, const T &rhs);

where T is the type used for the Vector<T>, and the returned type can implicitly cast to T.

So the following would probably work:

long l;
float f;
int i;
//.......

Vector<float> v1;
v2 = l * v1;
v3 = f * v2;
v4 = i * v3;


Related Topics



Leave a reply



Submit