Can't access private member in templated overloaded operator - c++

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)
}

Related

Generic friend operator== overload

I am currently stuck on a problem that I can't solve. I am a beginner in the world of c++.
For a homework, I have to create a generic class to represent a fraction like 5/6 or 11/4. This class is generic which allows to determine the type of the nominator and numerator (unsigned short, unsigned, unsigned long).
The goal is to be able to add, subtract, multiply, divide and compare fractions. In a first phase, I created a class and operator overloads allowing me to do everything that is required but only for instances of the class with the same type.
Now I would like to improve the existing code to be able to perform operations between fractions of different types like for example: Frac<unsigned> == Frac<unsigned short>. But there is something I don't understand in the syntax of overloading operators.
Let's take the == operator as an example:
template <typename T>
bool operator==(const Frac<T>& lhs, const Frac<T>& rhs) {
return (lhs.numerator == rhs.numerator && lhs.denominator == rhs.denominator);
}
template <typename T>
class Frac {
friend bool operator== <>(const Frac& lhs, const Frac& rhs);
private:
T numerator, denominator;
};
this is the current version that worked for the Fracs of the same type. But now I would like it to work for Fracs of a different type:
template <typename T>
class Frac;
template <typename T, typename U>
bool operator==(const Frac<T>& lhs, const Frac<U>& rhs){
return (lhs.numerator == rhs.numerator && lhs.denominator == rhs.denominator)
}
template <typename T>
class Frac {
friend bool operator== <>(const Frac& lhs, const Frac& rhs);
private:
T numerator, denominator;
};
But I have a compilation error when I want to compare Frac of different types... I don't understand and didn't find any solution explaining concretely what the problem was and how to implement this kind of solution properly.
Could you help me please ?
I hope my question is clear and complete.
You can do this the following way:
template <typename T>
class Frac {
//friend declaration
template <typename S, typename U> friend
bool operator==(const Frac<S>& lhs, const Frac<U>& rhs);
private:
T numerator, denominator;
};
template <typename T, typename U>
bool operator==(const Frac<T>& lhs, const Frac<U>& rhs){
return ((lhs.numerator == rhs.numerator) && (lhs.denominator == rhs.denominator));
}
Now you will be able to compare Frac for different types as you want.
I kept running into problems when I tried to implement the operator+. The compiler told me that it was impossible to access a private field when I tried to add two Frac of different type.
In order to solve this problem, I made my class friendly with itself so that all instances of Frac can access the private fields of the other instances even if the type is different. Is this a correct solution?
template <typename T>
class Frac {
//make Frac self-friend to make all instance of Frac friends each others
// not depending of Frac T type
template<typename U>
friend class Frac;
friend std::ostream& operator<< <T>(std::ostream& o, const Frac& rhs);
friend Frac operator+ <>(Frac lhs, const Frac& rhs);

Template class member vs. non-member template function ambiguity

I'm developing a header-only library for automatic/algorithmic differentiation. The goal is to be able to simply change the type of the variables being fed to a function and calculate first and second derivatives. For this, I've created a template class that allows the programmer to select the storage type for the private data members. Included is a snippet below with an offending operator overload.
template <typename storage_t>
class HyperDual
{
template <typename T> friend class HyperDual;
public:
template <typename T>
HyperDual<storage_t> operator+(const HyperDual<T>& rhs) const
{
HyperDual<storage_t> sum;
for (size_t i = 0; i < this->values.size(); i++)
sum.values[i] = this->values[i] + rhs.values[i];
return sum;
}
protected:
std::vector<storage_t> values;
};
Later on, to maximize the versatility, I provide template functions to allow interaction.
template <typename storage_t, typename T>
HyperDual<storage_t> operator+(const HyperDual<storage_t>& lhs, const T& rhs)
{
static_assert(std::is_arithmetic<T>::value && !(std::is_same<T, char>::value), "RHS must be numeric");
return HyperDual<storage_t>(lhs.values[0] + rhs);
}
template <typename storage_t, typename T>
HyperDual<storage_t> operator+(const T& lhs, const HyperDual<storage_t>& rhs)
{
static_assert(std::is_arithmetic<T>::value && !(std::is_same<T, char>::value), "LHS must be numeric");
return HyperDual<storage_t>(lhs + rhs.values[0]);
}
What I'm encountering is that the compiler is trying to instantiate the second non-member template function.
#include "hyperspace.h"
int main()
{
HyperDual<long double> one(1); // There is an appropriate constructor
HyperDual<double> two(2);
one + two;
return 0;
}
I get the static_assert generated error "LHS must be numeric" for this. How would I resolve the ambiguity?
use enable_if_t to make the non-member template can only be applied in the specific context?
template <typename storage_t, typename T, typename = enable_if_t<std::is_arithmetic<T>::value && !(std::is_same<T, char>::value)>>
HyperDual<storage_t> operator+(const HyperDual<storage_t>& lhs, const T& rhs)
{
static_assert(std::is_arithmetic<T>::value && !(std::is_same<T, char>::value), "RHS must be numeric");
return HyperDual<storage_t>(lhs.values[0] + rhs);
}
the static_assert may be duplicated here.
Ok. I found my own issue. It comes down to the difference between static_assert and std::enable_if
Replacing my template declaration and removing static_assert, I achieve equivalent functionality:
template <typename storage_t, typename T,
typename = typename std::enable_if<std::is_arithmetic<T>::value && !std::is_same<T, char>::value>::type>
HyperDual<storage_t> operator+(const T& lhs, const HyperDual<storage_t>& rhs)
{
return HyperDual<storage_t>(lhs + rhs.value());
}
(Small detail, but rhs.values[0] was replaced with rhs.value(). This had nothing to do with the template issue, but was related to member access.

Operator overload in class templates and friendship

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.

Implicit conversion of int to double in template operator*<>

I have a template class typically instantiated by <double>.
My header has something like:
template <typename T> class F;
// Non-member functions
template <typename T> const F<T> operator*(F<T> lhs, const F<T>& rhs);
template <typename T> const F<T> operator*(const F<T>& lhs, const T& rhs);
template <typename T>
class F
{
// blah blah
F<T>& operator*=(const F<T>& rhs);
F<T>& operator*=(const T& rhs_scalar);
// blah
friend const F<T> operator*(const F<T>& lhs, const T& rhs) { return F(lhs) *= rhs; }
friend const F<T> operator*(const T& lhs, const F<T>& rhs) { return F(rhs) *= lhs; }
};
In my .cpp file, I have something like:
#include "F.H"
// lots of template<typename T> returntype F<T>::function(args){ body }
template <typename T>
F<T>& F<T>::operator*=(const F<T>& rhs)
{
// check sizes, etc
// do multiplication
return *this;
}
template <typename T>
F<T>& F<T>::operator*=(const T& rhs_scalar)
{
for(auto &lhs : field_) // field_ is a vector holding values
{
lhs *= rhs_scalar;
}
return *this;
}
// Non-member parts
template <typename T> operator*(F<T> lhs, const F<T>& rhs)
{ lhs *= rhs; return lhs; }
template <typename T> operator*(const F<T>& lhs, const T& rhs)
{ return F<T>(lhs) *= rhs; }
template class F<double>;
template const F<double> operator*<double>(F<double>, const F<double>&);
This compiles and runs ok, and allows things like:
F<double> test(..);
test *= 2.5; test *= 10; test /= 2.5; test /= 10; // and so on
The question I have is: Can I reduce the number of declarations and definitions of my operators, whilst retaining the ability to implicitly promote an int to a double, etc? Can I rearrange the code so that the friend .. operator*(..) bodies are defined outside of the header file? (I suspect this would involve more specific instantiations in one or both of the header and the cpp file)
(Side note: how? Scott Meyer's Item 46 in 'Effective C++' describes implicit parameter conversion, but it seems like that describes allowing the construction of a temporary object to allow (in that case) Rational(int) * Rational_object_already_created;)
Can I reduce the number of declarations and definitions of my operators, whilst retaining the ability to implicitly promote an int to a double, etc?
You can do that by providing a converting constructor.
template <typename T2>
F(F<T2> const& f2 ) {...}

operator overloading as a friend function

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.