2017-03-02 4 views
3

Ich verwende boost-variant in meinen Projekten. In einem Szenario muss ich die in meinem boost-variant enthaltenen Typen in mehrere Klassen einteilen. Da ich in meiner Variante recht viele Typen habe, kam ich auf die Idee, innerhalb meines Besuchers mehrere Varianten zu definieren. Diese Varianten sind im Grunde die Typ-> Klassenzuordnung.Typen in Boost klassifizieren Variante mit Besucher kompiliert nicht

Der folgende Code veranschaulicht, was ich erreichen wollte.

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

Leider wird der Code nicht kompiliert. MSVC endet mit dem Compiler-Fehler C3066. Es gibt verschiedene Möglichkeiten, ein Objekt dieses Typs mit diesen Argumenten aufzurufen? Es könnte eine der drei operator() Funktionen sein.

Aber grundsätzlich kann ich 5 nur in die Variante IntegerTypes umwandeln.

Was könnte die Lösung für diese Art von Problem sein?

eigene Lösung

Nach dem Versuch boost-mpl verwenden ich an dieser Lösung gekommen. Die Funktion Contains stellt eine wiederverwendbare Software dar, die in anderen Teilen meines Programms enthalten sein könnte. Trotzdem wünschte ich mir, dass die Lösung näher an meinem ursprünglichen Quellcode wäre.

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

Antwort

2
#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

+0

kühlen. Ich habe diese Lösung jetzt auch abgeleitet. Es scheint der einzige praktikable Ansatz zu sein. Aber wenn du es liest, könntest du Kopfschmerzen bekommen. :-) Ich werde auch meine Lösung posten. Danke vielmals. – Aleph0

+1

@FrankSimon Weitere Alternativen sind: Tag-Dispatching und Hinzufügen einer separaten Überladung für jeden Typ –

+0

Keine Ahnung, was Tag-Dispatching ist. Ich denke, dass ich ein bisschen mehr lernen muss. :-) – Aleph0

Verwandte Themen