【问题标题】:Classify Types in Boost Variant using Visitor does not compile使用 Visitor 对 Boost Variant 中的类型进行分类无法编译
【发布时间】:2017-03-02 08:06:01
【问题描述】:

我在整个项目中都使用boost-variant。在一种情况下,我需要将 boost-variant 中包含的类型分类为几个类。由于我的变体中有很多类型,我想出了在我的访问者中定义几个变体的想法。这些变体基本上是类型->类映射。

下面的代码说明了我想要实现的目标。

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

    enum class Type {
        Integer,
        Float,
        NonNumeric
    };

    struct IsNum : public boost::static_visitor<Type> {
        typedef boost::variant<int, size_t> IntegerTypes;
        typedef boost::variant<float, double> FloatTypes;
        typedef boost::variant<std::string> NonNumericTypes;

        result_type operator()(const IntegerTypes& t) const {
            return Type::Integer;
        }

        result_type operator()(const FloatTypes& t) const {
            return Type::Float;
        }

        result_type operator()(const NonNumericTypes& t) const {
            return Type::NonNumeric;
        }
    };

    int main() {
        boost::variant<int, std::string, double> value;
        value = 5;
        IsNum visitor;
        auto result = value.apply_visitor(visitor);
    }

很遗憾,代码无法编译。 MSVC 以编译器错误C3066 结束。用这个参数调用这种类型的对象有不同的可能性吗?它可能是三个operator() 函数之一。

但基本上我只能将 5 转换为变体类型IntegerTypes

这类问题有什么解决办法?

自己的解决方案

在尝试使用boost-mpl 之后,我找到了这个解决方案。函数Contains 代表一个可重用的软件,它可能包含在我的程序的其他部分中。我仍然希望解决方案更接近我最初发布的源代码。

#include <iostream>
#include <boost/variant.hpp>
#include <string>
#include <boost/mpl/contains.hpp>

enum class Type {
    Integer,
    Float,
    NonNumeric
};

template<typename V, typename T>
using ContainsImpl = typename boost::mpl::contains<typename V::types, T>::type;

template<typename V, typename T>
bool Contains(const T&) {
    return ContainsImpl<V, T>::value;
}

struct IsNum : public boost::static_visitor<Type> {
    typedef boost::variant<int, size_t> IntegerTypes;
    typedef boost::variant<float, double> FloatTypes;
    typedef boost::variant<std::string> NonNumericTypes;

    template<typename T>
    result_type operator()(const T& t) const {
        if (Contains<IntegerTypes>(t)) {
            return Type::Integer;
        } else if (Contains<FloatTypes>(t)) {
            return Type::Float;
        } else if (Contains<NonNumericTypes>(t)) {
            return Type::NonNumeric;
        }

        return Type::NonNumeric;
    }
};

int main() {
    boost::variant<int, std::string, double> value;
    value = 5.;
    IsNum visitor;
    auto result = value.apply_visitor(visitor);
    if (result == Type::Integer) {
        std::cout << "Integer" << std::endl;
    }
    if (result == Type::Float) {
        std::cout << "Float" << std::endl;
    } 
    if (result == Type::NonNumeric) {
        std::cout << "Non Numeric" << std::endl;
    }
}

【问题讨论】:

    标签: c++ templates generics boost-mpl boost-variant


    【解决方案1】:
    #include <string>
    #include <boost/variant.hpp>
    #include <boost/mpl/list.hpp>
    #include <boost/mpl/contains.hpp>
    #include <boost/type_traits.hpp>
    
    enum class Type
    {
        Integer,
        Float,
        NonNumeric
    };
    
    struct IsNum : public boost::static_visitor<Type>
    {
        typedef boost::mpl::list<int, size_t> IntegerTypes;
        typedef boost::mpl::list<float, double> FloatTypes;
        typedef boost::mpl::list<std::string> NonNumericTypes;
    
        template <typename T>
        typename boost::enable_if<boost::mpl::contains<IntegerTypes, T>, result_type>::type
        operator()(const T& t) const
        {
            return Type::Integer;
        }
    
        template <typename T>
        typename boost::enable_if<boost::mpl::contains<FloatTypes, T>, result_type>::type
        operator()(const T& t) const
        {
            return Type::Float;
        }
    
        template <typename T>
        typename boost::enable_if<boost::mpl::contains<NonNumericTypes, T>, result_type>::type
        operator()(const T& t) const
        {
            return Type::NonNumeric;
        }
    };
    

    DEMO

    【讨论】:

    • 酷。我现在也得出了这个解决方案。这似乎是唯一可行的方法。但是阅读它可能会让您头疼。 :-) 我也会发布我的解决方案。非常感谢。
    • @FrankSimon 更多选择包括:标签调度和为每种类型添加单独的重载
    • 不知道什么是标签调度。我会认为我必须学习更多。 :-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-11
    • 2012-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多