C ++ 17构建双方变体运算符的最佳方法是什么?

问题描述 投票:2回答:1

我有一个项目,使用std::variant为可变长度类型:

using Length = std::variant<int, long, float, double, Fraction>;

Fraction类已经超载了大多数运营商。

我想创建算术运算符,如:

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;
}

这是有效的,但这是多余的,非美观的,并且可能没有那么快做大型操作过程。

c++ operator-overloading c++17 variant visitor
1个回答
4
投票

由于你的操作数属于变体类型,所以只需将visit放在一起:

Length operator* (Length lhs, Length rhs)
{
  return std::visit([](auto const &l, auto const &r) -> Length {
    return l * r;
  }, lhs, rhs);
}

标准库已经为您执行了所需的逻辑。

© www.soinside.com 2019 - 2024. All rights reserved.