Reputation: 833
I have a class template for a 3d vector class that looks kind of like (abbreviated):
template<typename T>
class vector3
{
public:
typedef vector3<T> self;
self& operator*(T& a);
self& operator*(T a);
T x,y,z;
};
Both of the operator* overloads 'self multiply' the vector times a scalar, and return *this.
I want to be able to use the class template like this:
vector3<double> vv;
double scalar;
vv*scalar;
vv*0.5;
The overload ambiguity is clear, and 'just get it to work' kind of solutions are available and have been discussed in other SA questions.
If you remove operator*(T& a), everything will compile, but you (at least in theory), lose some performance benefit from passing by value when you don't really need to (right?)
If you remove operator*(T a), you can't do vv*0.5.
If you rename one of them, you lose a lot of code clarity in cases where all these operations intuitively make sense, math-wise.
Is there any way to retain the pass by reference when it makes sense, but remove the overload ambiguity? What's the best way to make sure the vector3 template accommodates both expressions above?
Upvotes: 1
Views: 218
Reputation: 8066
You could create a method that takes an rvalue as parameter as Barry described.
Or your template parameter could be const
if the implementation does not modify it. In this case you could have only one method taking a const
reference:
self operator*(const T& a) const;
Upvotes: 0
Reputation: 2629
The best choice for you is
self operator * (const T& a) const;
There are three moments:
Using const T&
instead of T
or T&
. Modern compilers are smart, they will optimize the code and pass small types by value instead of reference.
The operator *
should not change the operands.
The operator *
should return a value but not a reference.
Upvotes: 3
Reputation: 303137
Just make the other one take an rvalue reference:
self operator*(T& a); // for 'scalar'
self operator*(T&& a); // for 0.5
Although, do you really have a different implementation for operator*
for the two different cases? You probably just want:
template <typename U,
typename = std::enable_if_t<std::is_same<std::decay_t<U>, T>::value>>
self operator*(U&& a); // for both
Note that operator*
should return a value. operator*=
should return a reference.
Upvotes: 0