Как упростить плюсовое действие на форсированном варианте?

У меня есть определение типа варианта повышения:

typedef boost::variant< bool, int, float, double> VariantType;

Я хочу реализовать на нем действие добавления/вычитания/умножения/разделения. Возьмем, к примеру, Добавить класс. Проблема заключается в том, что при добавлении нового типа в VariantType, например std::string, класс Add должен быть обновлен новым типом.

struct Add : public boost::static_visitor<VariantType> {
    template <typename T>
    T operator() (T a, T b) const {
        return a + b;
    }
    float operator() (int a, float b) const {
        return a + b;
    }
    float operator() (float a, int b) const {
        return a + b;
    }
    double operator() (int a, double b) const {
        return a + b;
    }
    double operator() (double a, int b) const {
        return a + b;
    }
    double operator() (float a, double b) const {
        return a + b;
    }
    double operator() (double a, float b) const {
        return a + b;
    }
    VariantType operator() (bool a, int b) const {
        throw std::invalid_argument("bool and int can't Plus");
    }
    VariantType operator() (bool a, float b) const {
        throw std::invalid_argument("bool and float can't Plus");
    }
    VariantType operator() (bool a, double b) const {
        throw std::invalid_argument("bool and double can't Plus");
    }
    VariantType operator() (int a, bool b) const {
        throw std::invalid_argument("int and bool can't Plus");
    }
    VariantType operator() (float a, bool b) const {
        throw std::invalid_argument("float and bool can't Plus");
    }
    VariantType operator() (double a, bool b) const {
        throw std::invalid_argument("double and bool can't Plus");
    }
};

Применение:

VariantType v1 = 1;
VariantType v2 = 2.1;
VariantType v3 = boost::apply_visitor(Add(), v1, v2);
cout<<boost::get<double>(v3)<<endl; //Print 2.2

Версия GCC — 4.8.2; Boost-версия — 1.57.0; Как просто добавить класс? Спасибо.


person liuzw    schedule 27.06.2016    source источник


Ответы (1)


Просто сделайте его полиморфным функтором:

Жить на Coliru

#include <boost/variant.hpp>
#include <iostream>

using VariantType = boost::variant<int, float, double, bool>;

struct Add : public boost::static_visitor<VariantType> {
    template <typename T, typename U>
    auto operator() (T a, U b) const -> decltype(a+b) { return a + b; }

    template <typename T> VariantType operator()(bool, T) const { throw std::invalid_argument("Can't to bool"); }
    template <typename T> VariantType operator()(T, bool) const { throw std::invalid_argument("Can't add bool"); }
    VariantType                     operator()(bool,bool) const { throw std::invalid_argument("Can't add bools"); }
};

int main() {
    std::cout << std::boolalpha;

    VariantType specimens[] = { int(42), 3.14f, 3.14, true };
    for (auto lhs : specimens)
        for (auto rhs : specimens)
        {
            try {
                std::cout << lhs << " + " << rhs << " ==  " << boost::apply_visitor(Add{}, lhs, rhs) << "\n";
            } catch(std::exception const& e) {
                std::cout << lhs << " + " << rhs << " ==> " << e.what() << "\n";
            }
        }
}

Отпечатки:

42 + 42 ==  84
42 + 3.14 ==  45.14
42 + 3.14 ==  45.14
42 + true ==> Can't add bool
3.14 + 42 ==  45.14
3.14 + 3.14 ==  6.28
3.14 + 3.14 ==  6.28
3.14 + true ==> Can't add bool
3.14 + 42 ==  45.14
3.14 + 3.14 ==  6.28
3.14 + 3.14 ==  6.28
3.14 + true ==> Can't add bool
true + 42 ==> Can't to bool
true + 3.14 ==> Can't to bool
true + 3.14 ==> Can't to bool
true + true ==> Can't add bools
person sehe    schedule 27.06.2016
comment
Я только что добавил живой пример со многими небольшими исправлениями/уточнениями /cc @DanielSchepler - person sehe; 28.06.2016