如何简化 boost 变体的加号操作?

Posted

技术标签:

【中文标题】如何简化 boost 变体的加号操作?【英文标题】:How to simplify the plus action on boost variant? 【发布时间】:2016-06-27 23:44:19 【问题描述】:

我有 boost 变体类型定义:

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; 如何简单地添加类?谢谢。

【问题讨论】:

【参考方案1】:

只要让它成为一个多态函子:

Live On 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

【讨论】:

我刚刚添加了一个带有许多小修复/说明 /cc @DanielSchepler 的实时示例

以上是关于如何简化 boost 变体的加号操作?的主要内容,如果未能解决你的问题,请参考以下文章

Boost:创建一个返回变体的函数

如何在 mpl::list 中声明 boost 递归变体?

C++ Boost 变体错误

为递归变体编写 boost::variant 访问者

如何使用变体创建几何图形

如何将 Postgres Hstore 数据类型转换为雪花对象或变体