I want to add some friend declarations to a class. For example, I want to add some functions of operator== ,operator <. So what I have to do is use the forward declarations:
template <typename >
class MyBlob;
template <typename T>
bool operator==(const MyBlob<T> &, const MyBlob<T>&);
template <typename T>
bool operator!=(const MyBlob<T> &, const MyBlob<T>&);
template <typename T>
bool operator<(const MyBlob<T> &, const MyBlob<T>&);
template <typename T>
class MyBlob
{
friend bool operator== <T>(const MyBlob<T> &lhs,const MyBlob<T> &rhs);
friend bool operator!= <T>(const MyBlob<T> &lhs,const MyBlob<T> &rhs);
friend bool operator< <T>(const MyBlob<T> &lhs,const MyBlob<T> &rhs);
//other things
};
This is annoying that I have to use template <typename T> for three times. And this really reduce the readability.
So, is there any method to make the forward declaration more simple? Or can I have some method to declare these things in one place just like the ordinary function?
If this can't be done, Is using typedef to simplify the template <typename T> a good idea?
You can try defining friend operators within the class declaration:
template <typename T>
class MyBlob {
friend bool operator== (const MyBlob& lhs, const MyBlob& rhs) {
// ...
}
friend bool operator!= (const MyBlob& lhs, const MyBlob& rhs) {
// ...
}
friend bool operator< (const MyBlob& lhs, const MyBlob& rhs) {
// ...
}
// ...
};
Related
In this code, why is it not possible to access the private field of my class in the operator overload ?
(Note that this is only a MRE, not the full code)
template <typename T>
class Frac
template <typename T, typename U>
Frac<T> operator+ (Frac<T> lhs,const Frac<U>& rhs);
template <typename T, typename U>
bool operator==(const Frac<T>& lhs, const Frac<U>& rhs);
template <typename T>
class Frac {
template<typename>
friend class Frac;
friend Frac operator+ <>(Frac lhs,const Frac& rhs);
friend bool operator== <>(const Frac& lhs, const Frac& rhs);
private:
T numerator, denominator;
};
template <typename T, typename U>
Frac<T> operator+(Frac<T> lhs,const Frac<U>& rhs) {
lhs.denominator += rhs.denominator;
return lhs;
}
template <typename T, typename U>
bool operator==(const Frac<T>& lhs, const Frac<U>& rhs) {
return (lhs.numerator == rhs.numerator && lhs.denominator == rhs.denominator);
}
When I compile the compiler tells me that it is not possible to access the denominator and numerator fields because they are private. However the overload is indicated as friendly. The class is also indicated as friendly so that all instances of the class whatever the type are friendly.
Could someone explain me what the problem is and how to solve it?
To make each instance of
template <typename T, typename U>
bool operator==(const Frac<T>& lhs, const Frac<U>& rhs);
a friend, you need to be just as verbose in your friend declaration. Copy this declaration and stick "friend" in it. There are two quirks. First, template has to come before friend, so you'll be adding the keyword in the middle of the declaration. Second, T is already being used as the template parameter to the class, so you should choose a different identifier to avoid shadowing (I'll use S).
template <typename S, typename U>
// ^^^
friend bool operator==(const Frac<S>& lhs, const Frac<U>& rhs);
// ^^^^^^ ^^^
Without this change, you are saying that the friend of Frac<T> is an operator that takes two Frac<T> parameters (the same T).
it is not possible to access the denominator and numerator fields because they are private.
Yes, you haven't made the free functions friends. You've made the classes friends, but that doesn't help the free functions. One simpler solution is to define them in the class definition.
Example:
template <typename U>
friend Frac operator+(Frac lhs, const Frac<U>& rhs) {
lhs.denominator += rhs.denominator;
return lhs;
}
However, operator+ could be implemented as a free function without any friendship if you instead make operator+= a member function. The friendship between all Frac<>s has already been established so no additional friend declarations are needed.
Example:
#include <iostream>
#include <utility>
template <typename T>
class Frac {
public:
template <typename> // be friends with all Frac's
friend class Frac;
Frac() = default; // needed because for the templated converting ctor below
// a converting constructor from any Frac:
template<class U>
explicit Frac(const Frac<U>& rhs) :
numerator(rhs.numerator), denominator(rhs.denominator) {}
template <typename U>
Frac& operator+=(const Frac<U>& rhs) {
denominator += rhs.denominator; // ok: rhs has befriended Frac<T>
return *this;
}
template <typename U>
bool operator==(const Frac<U>& rhs) const {
// ok: rhs has befriended Frac<T> here too
return numerator == rhs.numerator && denominator == rhs.denominator;
}
private:
T numerator{}, denominator{};
};
// This free function doesn't need to be a friend. It uses the member function
// operator+=
// The returned type, Fact<R>, is deduced by fetching the type you'd gotten
// if you add a T and U.
template<typename T, typename U,
typename R = decltype(std::declval<T>() + std::declval<U>())>
Frac<R> operator+(const Frac<T>& lhs, const Frac<U>& rhs) {
Frac<R> rv(lhs); // use the converting constructor
rv += rhs;
return rv;
}
int main() {
Frac<int> foo;
Frac<double> bar;
auto r = foo + bar; // r is a Frac<double> (int + double => double)
}
I am trying to implement an overload for operator!= that compares two objects of different types (InnerA and InnerB). Both of the types are defined as nested classes within a template class (Outer). The overload needs to be a friend of both classes as it accesses private fields from each.
template<typename Type> class Outer
{
public:
class InnerA;
class InnerB;
};
template<typename Type> bool operator!=(const typename Outer<Type>::InnerA& lhs, const typename Outer<Type>::InnerB& rhs);
template<typename Type> class Outer<Type>::InnerA
{
const int val = 0;
friend bool operator!=<>(const InnerA& lhs, const typename Outer<Type>::InnerB& rhs);
};
template<typename Type> class Outer<Type>::InnerB
{
const int val = 1;
friend bool operator!=<>(const typename Outer<Type>::InnerA& lhs, const InnerB& rhs);
};
template<typename Type> bool operator!=(const typename Outer<Type>::InnerA& lhs, const typename Outer<Type>::InnerB& rhs)
{
return lhs.val != rhs.val;
}
int main()
{
bool b = Outer<int>::InnerA() != Outer<int>::InnerB();
}
The above code fails to compile, emitting:
In instantiation of 'class Outer<int>::InnerA':
34:33: required from here
15:17: error: template-id 'operator!=<>' for 'bool operator!=(const Outer<int>::InnerA&, const Outer<int>::InnerB&)' does not match any template declaration
In instantiation of 'class Outer<int>::InnerB':
34:57: required from here
22:17: error: template-id 'operator!=<>' for 'bool operator!=(const Outer<int>::InnerA&, const Outer<int>::InnerB&)' does not match any template declaration
In function 'int main()':
34:35: error: no match for 'operator!=' (operand types are 'Outer<int>::InnerA' and 'Outer<int>::InnerB')
34:35: note: candidate is:
26:30: note: template<class Type> bool operator!=(const typename Outer<Type>::InnerA&, const typename Outer<Type>::InnerB&)
26:30: note: template argument deduction/substitution failed:
34:57: note: couldn't deduce template parameter 'Type'
While there might be better ways to achieve a similar result, I'm curious as to what precisely is wrong with my code. Thanks!
template<typename Type> class Outer<Type>::InnerA
{
friend bool operator!=(const InnerA& lhs, const typename Outer<Type>::InnerB& rhs) { return true; }
};
template<typename Type> class Outer<Type>::InnerB
{
friend bool operator!=(const typename Outer<Type>::InnerA& lhs, const InnerB& rhs) { return true; }
};
these are non-template friends. They also conflict. So implement one of them, omit the other.
They will be found via ADL.
I found the following workaround, refactoring the overload as a method of one of the nested classes:
template<typename Type> class Outer
{
public:
class InnerA;
class InnerB;
};
template<typename Type> class Outer<Type>::InnerA
{
const int val = 0;
public:
bool operator!=(const typename Outer<Type>::InnerB& other);
};
template<typename Type> class Outer<Type>::InnerB
{
const int val = 1;
friend bool Outer<Type>::InnerA::operator!=(const InnerB& other);
};
template<typename Type> bool Outer<Type>::InnerA::operator!=(const typename Outer<Type>::InnerB& other)
{
return val != other.val;
}
int main()
{
bool b = Outer<void>::InnerA() != Outer<void>::InnerB();
}
However, I am still curious if the same can be accomplished using a non-member friend function as in the question.
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.
Suppose I have a small class template as below
template<typename T> class SillyClass {
public:
SillyClass(const T val);
SillyClass(const SillyClass& other);
private:
T data;
};
Now I add the following definitions declarations:
template<typename T> class SillyClass {
public:
SillyClass(const T val);
SillyClass(const SillyClass& other);
SillyClass<T> operator+ (const SillyClass& other);
SillyClass<T> operator+ (const T& val);
private:
T data;
};
and now (after I write the appropriate definitions) I can do things like
SillyClass<int> a(1);
SillyClass<int> b(a);
SillyClass<int> c = a + b;
SillyClass<int> d = a + 3;
So far, so good. However, to be able to write something like
SillyClass<int> e = 3 + a;
I found that must add the following declaration to my class
template<typename T2> friend SillyClass<T2> operator+
(const T2& val, const SillyClass<T2>& other);
so it now reads
template<typename T> class SillyClass {
public:
SillyClass(const T val);
SillyClass(const SillyClass& other);
SillyClass<T> operator+ (const SillyClass& other);
SillyClass<T> operator+ (const T& val);
template<typename TT> SillyClass<TT> friend operator+
(const TT& val, const SillyClass<TT>& other);
private:
T data;
};
I didn't find this in a book and I'd like some help to understand what's happening on this last declaration. For instance, with what is my class being befriended here? Why the additional template declaration? What alternatives do I have in terms of different declarations that lead to the same result (being able to perform 3+a, say)?
Thanks.
with what is my class being befriended here? Why the additional template declaration?
The following expression declared inside your class is a friend declaration:
template<typename TT> SillyClass<TT> friend operator+
(const TT& val, const SillyClass<TT>& other);
The above expression declares your class a friend with a family of overloaded operator+s that take as their left-hand-side parameter a type TT and as their right-hand-side an object SillyClass<TT>. Note though that this is a declaration and not a definition. That is, in order for this to work the template overloaded operator+, must be defined.
What alternatives do I have in terms of different declarations that
lead to the same result (being able to perform 3+a, say)?
For binary operators in order for them to be symmetric must be declared outside the class definition as free functions, and in order to have access to the private members of their class parameters you declare them as a friend function of the respective class.
Based on these lines I would go along with the following implementation:
template<typename T> class SillyClass {
T data;
public:
SillyClass(const T val) : data(val) {}
SillyClass(const SillyClass& other) : data(other.data) {}
template<typename T1, typename T2>
friend SillyClass<typename std::common_type<T1, T2>::type>
operator+(SillyClass<T1> const &lsh, SillyClass<T2>& rhs);
template<typename T1, typename T2>
friend SillyClass<typename std::common_type<T1, T2>::type>
operator+(SillyClass<T1> const &lsh, T2 const &rhs);
template<typename T1, typename T2>
friend SillyClass<typename std::common_type<T1, T2>::type>
operator+(T1 const &rhs, SillyClass<T2> const &rsh);
};
template<typename T1, typename T2>
SillyClass<typename std::common_type<T1, T2>::type>
operator+(SillyClass<T1> const &lhs, SillyClass<T2>& rhs) {
return SillyClass<typename std::common_type<T1, T2>::type>(lhs.data + rhs.data);
}
template<typename T1, typename T2>
SillyClass<typename std::common_type<T1, T2>::type>
operator+(SillyClass<T1> const &lhs, T2 const &rhs) {
return SillyClass<typename std::common_type<T1, T2>::type>(lhs.data + rhs);
}
template<typename T1, typename T2>
SillyClass<typename std::common_type<T1, T2>::type>
operator+(T1 const &lhs, SillyClass<T2> const &rhs) {
return SillyClass<typename std::common_type<T1, T2>::type>(rhs.data + lhs);
}
Live Demo
Instead of only declaring your operator in class, you can define the friend operator inside your class:
SillyClass<T> friend operator+(const T& val, const SillyClass<T>& other)
{
// define it here
}
This way, for each instance of your class, a corresponding friend will be generated. The whole thing works based on something called friend name injection.
Now back to your problem. If you just use an in-class declaration
friend operator+(const T& val, const SillyClass<T>& other);
and then outside your class you define
template<typename T>
friend operator+(const T& val, const SillyClass<T>& other)
you'll get a linker error. Why? Because suppose T=int when you instantiate the class. Then the declaration in your class will read as
friend operator+(const int& val, const SillyClass<int>& other);
and will be a better match than the above template definition whenever you invoke your operator+ on SillyClass<int> and some int. So the linker won't be able to find the definition of the required int instantiation, hence a linker error. On the other hand, the solution I proposed at the beginning of the answer guarantees a corresponding definition for every type, so it will work without any headaches.
I create a template class and want to overload an operator + (several times). I do this in the following way
template <typename T> class Polynomial;
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar);
....
template <typename T>
class Polynomial {
....
public:
....
Polynomial operator +(const Polynomial& other) const {
// impelementation
}
friend const Polynomial<T> operator + <> (const Polynomial<T>& poly, const T& scalar);
};
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar) {
// implementation
}
However, I got the following error (which corresponds to the line that begins with 'friend')
problem2.cpp:282:45: error: declaration of ‘operator+’ as non-function
problem2.cpp:282:45: error: expected ‘;’ at end of member declaration
problem2.cpp:282:47: error: expected unqualified-id before ‘<’ token
Following Raxvan's advise, I've changed the code
template class Polynomial;
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar);
template <typename T>
ostream& operator <<(ostream& out, const Polynomial<T>& other);
....
template <typename T>
class Polynomial {
....
public:
....
friend ostream& operator << <> (ostream& out, const Polynomial<T>& other);
Polynomial operator +(const Polynomial& other) const {
// impelementation
}
template <typename NOT_T>
friend const Polynomial<NOT_T> operator +(const Polynomial<NOT_T>& poly, const NOT_T& scalar);
};
template <typename T>
ostream& operator <<(ostream& out, const Polynomial<T>& other) {
// implementation
}
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar) {
// implementation
}
And in this code I don't have problems with operator << as I had with operator +. Can anyone explain the defference?
The problem is subtle. Your syntax is very close to being
correct. I think your friend declaration should be:
friend Polynominal<T> const operator+<T>( ... );
but both VC++ and g++ accept:
friend Polynominal<> const operator+<T>( ... );
when they can see the declaration:
template <typename T>
const Polynomial<T> operator+(const Polynomial<T>& poly, const T& scalar);
(I can't find anything in the standard to justify this off hand,
but since both VC++ and g++ do it, I suppose that it's something
I've missed.)
And therein lies the problems. The declaration at namespace
scope of operator+ is hidden by the in-class definition. The
compiler complains because the operator+ it finds (the in
class definition) isn't a template itself (although it is
a member of a class template).
If you don't have the problem with operator<<, it's because
you don't have a member function with the same name.
There are several ways of solving this problem. The simplest is
probably to make all of the operator+ friends. Or not: the
most common approach to this is to implement operator+ in
terms of operator+= (which should be a member, in all cases).
In which case, operator+ doesn't have to be a friend.
Or you don't make operator+ a template at all, but definite it
inside your class template:
template <typename T>
class Polynomial
{
friend Polynomial operator+( Polynomial const& lhs, Polynomial const& rhs )
{
// ...
}
friend Polynomial operator+( Polynomial const& lhs, T const& rhs )
{
// ...
}
friend Polynomial operator+( T const& lhs, Polynomial const& rhs )
{
// ...
}
}
(Note that the functions being defined are not templates, but
separate overloaded non-template functions, one for each
instantiation of Polynomial. But the results end up being the
same.)
In this case, you probably would want to have a member function,
called by the operator+ functions, which would do the actual
work; you don't want too much code directly inline like this.
Your operator+ is a function template, to make this a friend, you need to declare it fully including the template parameters, however with a different template parameter, for example:
#include <iostream>
template <typename T> class Polynomial;
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar);
template <typename T>
class Polynomial {
public:
Polynomial operator +(const Polynomial& other) const {
std::cout << "inline +" << std::endl;
}
// Here introduce a different type to indicate that this is a template...
template <typename U>
friend const Polynomial<U> operator + (const Polynomial<U>& poly, const U& scalar);
};
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar) {
std::cout << "friend +" << std::endl;
}
int main(void)
{
Polynomial<int> f;
f = f + 1;
f = f + 1.; // this fails
f = f + Polynomial<int>();
}
You have to have the same definition when you label a function as friend, this includes the template used above with another type , not T
template <typename T> class Polynomial;
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar);
template <typename T>
class Polynomial {
public:
template < class NOT_T> //must respect the deffinition from above
friend const Polynomial<NOT_T> operator + (const Polynomial<NOT_T>& poly, const NOT_T& scalar);
};
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar)
{
//...
}
Edit:
For a simplified explanation i have changed the function to foo and bar to illustrate the difference in declarations:
template <typename T> class Polynomial;
template <typename T>
void bar(const Polynomial<T>& );
void foo(const Polynomial<float> & );//foo for speciffic float
template <typename T>
class Polynomial {
public:
template <typename> //this is also valid declaration;
friend void bar(const Polynomial<T> & );
//it just has to have template because it's a template functions declaration
//not a valid declaration:
//friend void bar <> (const Polynomial<T> & );
//this declaration has no template;
//it refers to a foo function specific to Polynomial<T> type
//so if you use Polynomial<float> there must be a foo for floats
friend void foo(const Polynomial<T> &);
};
template <class T>
void bar(const Polynomial<T>&)
{
}
void foo(const Polynomial<float> &)
{
}
void main()
{
Polynomial<float> pf;
Polynomial<int> pi;
foo(pi);//error since there is not **foo** declared for int
foo(pf);//ok; we have **foo** for Polynomial<float>
bar(pf);
bar(pi);//both ok since bar is templated function;
}
Raxvan.
Why does this code give me a linker error and how do I fix it?
Undefined symbols for architecture x86_64: "operator==(foo const&, foo const&)", referenced from: _main in main.o ld: symbol(s) not found for architecture x86_64
template<typename T>
class foo {
//friends get access to the private member t
friend bool operator==(const foo<T> &lhs, const foo<T> &rhs);
T t;
};
template<typename T>
bool operator==(const foo<T> &lhs, const foo<T> &rhs) {
return lhs.t == rhs.t;
}
int main(int,char**) {
foo<int> f1, f2;
if (f1 == f2)
;
return 0;
}
Here is a fix of your code:
template<typename T>
class foo; // Forward declaration
template<typename T> // Need to define or declare this before the class
bool operator==(const foo<T> &lhs, const foo<T> &rhs) {
return lhs.t == rhs.t;
}
template<typename T>
class foo {
// Notice the little <> here denoting a specialization
friend bool operator==<>(const foo<T> &lhs, const foo<T> &rhs);
T t;
};
operator== is a function template, but the friendship declaration doesn't reflect this. This is one way to fix it:
template <class U>
friend bool operator==(const foo<U> &lhs, const foo<U> &rhs);
One very minor glitch is that it gives operator==<int> friend-access to foo<string>. For this reason, I think #JesseGood's fix is cleaner, albeit (paradoxically) more verbose.
You need to specify the template types again, but different to the class template type:
template<typename V>
friend bool operator==(const foo<V> &lhs, const foo<V> &rhs);
When overloading operators, avoid using friend functions; you'll want to define your function as a public class member, and make it take only one argument (not two).
template<typename T>
class foo {
//public function allowing access to the private member t
public:
bool operator==( foo<T> &rhs)
{
return t == rhs.t;
}
private:
T t;
};
int main(int,char**) {
foo<int> f1, f2;
if (f1 == f2)
;
return 0;
}