Reputation: 1149
For example, I have 2 structures: a 2D vector and a 3D vector with defined += operators:
struct Vector2
{
double x;
double y;
....
Vector2& operator+=(const Vector2& vector);
....
};
struct Vector3
{
double x;
double y;
double z;
....
Vector3& operator+=(const Vector3& vector);
....
};
It is trivial to implement '+' operators for these structures using the corresponding '+=' operators:
Vector2 operator+(const Vector2& vector1, const Vector2& vector2)
{
Vector2 result(vector1);
result += vector2;
return result;
}
Vector3 operator+(const Vector3& vector1, const Vector3& vector2)
{
Vector3 result(vector1);
result += vector2;
return result;
}
I'd like to unify these 2 functions and replace them with one template function:
template <class T>
T operator+(const T& vector1, const T& vector2)
{
T result(vector1);
result += vector2;
return result;
}
But this function is so general that it makes operator+ ambiguous for other classes. I tried to make this template applicable only for Vector2 and Vector3 structs using custom type traits and static_assert:
template <class T>
T operator+(const T& vector1, const T& vector2)
{
static_assert(suitable_type_for_this_function<T>::value, "Unsupported type!");
...
}
But it does not hide declaration of the template operator for other classes. Therefore this approach again leads to ambiguity.
How can I implement such a unified operator+, but define it only for these 2 specific types?
Upvotes: 0
Views: 154
Reputation: 275800
template<class D>
struct add_using_increment {
using Self=add_using_increment<D>;
friend D operator+(Self&& lhs, Self const& rhs){
lhs+=rhs;
return std::move(lhs.self());
}
friend D operator+(Self const& lhs, Self const& rhs){
return D(lhs.self())+rhs;
}
private:
D&self(){ return *static_cast<D*>(this); }
D const&self()const{ return *static_cast<D const*>(this); }
};
Now just do this:
struct Vector2:add_using_increment<Vector2>
Altenratively you can use SFINAE to restrict your template argument to (A) being one of a fixed set, (B) having a void increment( lhs&, rhs const& )
function defined on it, (C) having a +=
defined on it.
(C) is too greedy.
You can also use boost.operators which is an industrial strength version of my add_using_increment
.
Upvotes: 2
Reputation: 172994
You can apply SFINAE, use std::enable_if
with std::is_same
to constrain the types allowed on T
.
template <class T>
std::enable_if_t<std::is_same_v<T, Vector2> || std::is_same_v<T, Vector3>, T>
operator+(const T& vector1, const T& vector2);
Upvotes: 1