C ++ 17在两侧构建具有变体的运算符的最佳方法?
C++17 Best way to build operators with variant on two sides?
我有一个项目使用 std::variant
作为可变长度类型:
using Length = std::variant<int, long, float, double, Fraction>;
Fraction
class 已经使大多数运算符超载。
我想创建像这样的算术运算符:
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);
Length operator> (Length lhs, Length rhs);
Length operator>= (Length lhs, Length rhs);
Length operator< (Length lhs, Length rhs);
Length operator<= (Length lhs, Length rhs);
这是我用 std::visit
方法完成工作的模式。
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;
}
可行,但这是多余的、不美观的,而且进行大型操作过程可能不会那么快。
由于您的操作数是 variant 类型,因此只需 visit 它们一起:
Length operator* (Length lhs, Length rhs)
{
return std::visit([](auto const &l, auto const &r) -> Length {
return l * r;
}, lhs, rhs);
}
标准库已经为您执行了所需的逻辑。
我有一个项目使用 std::variant
作为可变长度类型:
using Length = std::variant<int, long, float, double, Fraction>;
Fraction
class 已经使大多数运算符超载。
我想创建像这样的算术运算符:
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);
Length operator> (Length lhs, Length rhs);
Length operator>= (Length lhs, Length rhs);
Length operator< (Length lhs, Length rhs);
Length operator<= (Length lhs, Length rhs);
这是我用 std::visit
方法完成工作的模式。
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;
}
可行,但这是多余的、不美观的,而且进行大型操作过程可能不会那么快。
由于您的操作数是 variant 类型,因此只需 visit 它们一起:
Length operator* (Length lhs, Length rhs)
{
return std::visit([](auto const &l, auto const &r) -> Length {
return l * r;
}, lhs, rhs);
}
标准库已经为您执行了所需的逻辑。