I have a project that use a std::variant
for a variable length types :
using Length = std::variant<int, long, float, double, Fraction>;
The Fraction
class already overload most of the operators.
I want to create arithmetics operators like :
Length operator+ (Length lhs, Length rhs);
Length operator- (Length lhs, Length rhs);
Length operator* (Length lhs, Length rhs);
Length operator/ (Length lhs, Length rhs);
But comparison operators too :
Length operator== (Length lhs, Length rhs);
Length operator!= (Length lhs, Length rhs);
Length operator> (Length lhs, Length rhs);
Length operator>= (Length lhs, Length rhs);
Length operator< (Length lhs, Length rhs);
Length operator<= (Length lhs, Length rhs);
This is the pattern I use to do the job with std::visit
method.
Length operator* (Length lhs, Length rhs)
{
Length res;
std::visit([&res, rhs](auto& left)
{
using T = std::remove_cv_t<std::remove_reference_t<decltype(left)>>;
if constexpr (std::is_same_v<T, int>)
{
std::visit([&res, left](auto& right)
{
using T = std::remove_cv_t<std::remove_reference_t<decltype(right)>>;
if constexpr (std::is_same_v<T, int>) { res = left * right; } else
if constexpr (std::is_same_v<T, long>) { res = left * right; } else
if constexpr (std::is_same_v<T, float>) { res = left * right; } else
if constexpr (std::is_same_v<T, double>) { res = left * right; } else
if constexpr (std::is_same_v<T, Fraction>) { res = left * right; }
},
rhs);
}
else
if constexpr (std::is_same_v<T, long>)
{
std::visit([&res, left](auto& right)
{
using T = std::remove_cv_t<std::remove_reference_t<decltype(right)>>;
if constexpr (std::is_same_v<T, int>) { res = left * right; } else
if constexpr (std::is_same_v<T, long>) { res = left * right; } else
if constexpr (std::is_same_v<T, float>) { res = left * right; } else
if constexpr (std::is_same_v<T, double>) { res = left * right; } else
if constexpr (std::is_same_v<T, Fraction>) { res = left * right; }
},
rhs);
}
else
if constexpr (std::is_same_v<T, float>)
{
std::visit([&res, left](auto& right)
{
using T = std::remove_cv_t<std::remove_reference_t<decltype(right)>>;
if constexpr (std::is_same_v<T, int>) { res = left * right; } else
if constexpr (std::is_same_v<T, long>) { res = left * right; } else
if constexpr (std::is_same_v<T, float>) { res = left * right; } else
if constexpr (std::is_same_v<T, double>) { res = left * right; } else
if constexpr (std::is_same_v<T, Fraction>) { res = left * right; }
},
rhs);
}
else
if constexpr (std::is_same_v<T, double>)
{
std::visit([&res, left](auto& right)
{
using T = std::remove_cv_t<std::remove_reference_t<decltype(right)>>;
if constexpr (std::is_same_v<T, int>) { res = left * right; } else
if constexpr (std::is_same_v<T, long>) { res = left * right; } else
if constexpr (std::is_same_v<T, float>) { res = left * right; } else
if constexpr (std::is_same_v<T, double>) { res = left * right; } else
if constexpr (std::is_same_v<T, Fraction>) { res = left * right; }
},
rhs);
}
else
if constexpr (std::is_same_v<T, Fraction>)
{
std::visit([&res, left](auto& right)
{
using T = std::remove_cv_t<std::remove_reference_t<decltype(right)>>;
if constexpr (std::is_same_v<T, int>) { res = left * right; } else
if constexpr (std::is_same_v<T, long>) { res = left * right; } else
if constexpr (std::is_same_v<T, float>) { res = left * right; } else
if constexpr (std::is_same_v<T, double>) { res = left * right; } else
if constexpr (std::is_same_v<T, Fraction>) { res = left * right; }
},
rhs);
}
},
lhs);
return res;
}
That works, but this is redundant, non esthetic, and probably not so fast to do large operation process.
Since your operands are of the variant type, just visit them both together:
Length operator* (Length lhs, Length rhs)
{
return std::visit([](auto const &l, auto const &r) -> Length {
return l * r;
}, lhs, rhs);
}
The standard library already performs the required logic for you.