I'm having a class which needs to have multiple overloads of the * operator. Some of these need to be declared as friends so I can have the class type as second argument. This is an example of a class which encounters the problem I'm about to present:
#pragma once
template<typename T>
class Example;
template<typename T>
Example<T> operator*(T value, Example<T> obj);
template<typename T>
class Example
{
private:
T m_data;
public:
Example(T);
friend Example operator*<T>(T, Example);
Example operator*(const T& other);
};
template<typename T>
Example<T> operator*(T value, Example<T> obj)
{
return value * obj.m_data;
}
template<typename T>
Example<T>::Example(T data) :m_data(data) { }
template<typename T>
Example<T> Example<T>::operator*(const T& other)
{
return Example(m_data * other.m_data);
}
This works but If I change:
template<typename T>
class Example
{
private:
T m_data;
public:
Example(T);
friend Example operator*<T>(T, Example);
Example operator*(const T& other);
};
with
template<typename T>
class Example
{
private:
T m_data;
public:
Example(T);
Example operator*(const T& other);
friend Example operator*<T>(T, Example);
};
I start getting a bunch of errors even though all I'm doing is swapping those 2 lines containing the declarations of the operator overloads. Can you explain me what is going on here? This makes no sense to me.
Code that generated error:
Example<int> a(2);
2 * a;
Errors:
unexpected token(s) preceding';' syntax error missing':' before '<' 'operator*': redefinition: previous definition was 'function' 'operator*': looks like a function but there is no parameter list. '*': uses 'Example<int>' which is being defined '*': friend not permitted on data declarations
https://godbolt.org/z/j4zYTP8n7
There are two different things named operator*
in your code. There is the function template, which you declare before Example
, and the member function of Example
. The syntax operator*<T>
, a template specialization, is only valid when operator*
refers to the template, but not to the member function. In your first declaration, where the friend
comes before the member function, the operator*
member function has not been declared at the point where the compiler sees operator*<T>
, so it resolves the name to the function template declared before Example
and everything is fine (the specific specialization operator*<T>
becomes a friend
of each Example<T>
).
template<typename T>
Example<T> operator*(T value, Example<T> obj); // <-\ ...finds a template, so no syntax error
// |
template<typename T> // |
class Example { // |
T m_data; // |
public: // |
Example(T); // |
friend Example operator*<T>(T, Example); // >-/ looking up this name...
Example operator*(const T& other);
};
Do it the other way and instead operator*<T>
is taken to refer to the member function, which is not a template, and you get a syntax error (specifically, I think it's trying to somehow interpret it as operator* < T >
where the <
and >
are the actual less-than/greater-than operators).
template<typename T>
class Example {
T m_data;
public:
Example(T);
Example operator*(const T& other); // <-\ ...does not find a template; ouch!
friend Example operator*<T>(T, Example); // >-/ looking up this name...
};
With your help I've reached the following solution. I was also able to get rid of the redundancy of declarations from the first lines. This is the final product:
template<typename T>
class Example
{
private:
T m_data;
public:
Example(T);
Example operator*(const T& other);
template<typename T>
friend Example<T> operator*(T, Example<T>);
};
template<typename T>
Example<T> operator*(T value, Example<T> obj)
{
return value * obj.m_data;
}
template<typename T>
Example<T>::Example(T data) :m_data(data) { }
template<typename T>
Example<T> Example<T>::operator*(const T& other)
{
return Example(m_data * other.m_data);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With