2016-06-03 20 views
2

In einem meiner Projekte aktiv bin ich boost::variant und ich stolperte über eine Frage, die ich nicht allein lösen konnte. Ich habe eine boost::variant, die atomare Datentypen und STL-Container dieser atomaren Datentypen enthalten könnte.Boost Variante Besucher mit variadic Vorlage Argumente

Jetzt wollte ich die Größe einer Instanz des zuvor definierten boost::variant Typs berechnen. Es gibt grundsätzlich nur zwei mögliche Funktionen. Der Typ eines atomaren Datentyps ist einfach 1, während die Größe eines STL-Containers als die Anzahl der darin enthaltenen Elemente definiert ist.

Mit nur 2 Atom dataypes I implementiert den folgenden Code:

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

typedef boost::variant<int, double, std::vector<int>, std::vector<double> > TVariant; 

struct sizeVisitor : boost::static_visitor<size_t> { 
    size_t operator()(int&) { 
    return 1; 
    } 
    size_t operator()(double&) { 
    return 1; 
    } 

    size_t operator()(std::vector<int>& c) { 
    return c.size(); 
    } 

    size_t operator()(std::vector<double>& c) { 
    return c.size(); 
    } 
} ; 


int main(int argc, char **args) { 
    sizeVisitor visitor; 
    TVariant var=5; 
    std::cout << boost::apply_visitor(visitor, var) << std::endl; 
    std::vector<int> vector; 
    vector.push_back(6); 
    vector.push_back(2); 
    var=vector; 
    std::cout << boost::apply_visitor(visitor, var) << std::endl; 
} 

Da die Zahl der atomaren Datentypen steigt ich eine Menge Code-Duplizierung haben. Ich muss für jeden neuen atomaren Datentyp zwei weitere Funktionen deklarieren, was prohibitiv sein kann.

Es wäre schön, wenn der folgende Code kompilieren würde:

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

typedef boost::variant<int, double, std::vector<int>, std::vector<double> > TVariant; 

struct sizeVisitor : boost::static_visitor<size_t> { 
    size_t operator()(boost::variant<int,double>&) { 
    return 1; 
    } 

    size_t operator()(boost::variant<std::vector<int>,std::vector<double>>& c) { 
    return c.size(); 
    } 

} ; 


int main(int argc, char **args) { 
    sizeVisitor visitor; 
    TVariant var=5; 
    std::cout << boost::apply_visitor(visitor, var) << std::endl; 
    std::vector<int> vector; 
    vector.push_back(6); 
    vector.push_back(2); 
    var=vector; 
    std::cout << boost::apply_visitor(visitor, var) << std::endl; 
} 

Was könnte die nächste Umsetzung der zweiten sein, leider nicht-Compilierung, Besucher?

Antwort

5

verwenden nur zwei Funktionsschablonen für operator():

struct sizeVisitor 
    : boost::static_visitor<size_t> 
{ 
    template <class T> 
    size_t operator()(T const&) { 
     return 1; 
    } 

    template <class T> 
    size_t operator()(std::vector<T> const& v) { 
     return v.size(); 
    }  
}; 

Die Vorlage Teilordnungsregeln wird sichergestellt, dass die richtige aufgerufen wird.

+0

Wow. Das ist eine sehr offensichtliche Lösung. Danke vielmals. Ich frage mich, ob es auch eine Lösung für das allgemeinere Problem gibt, wo ich die Menge von Typen einer gegebenen "boost :: variante" in zwei Teilmengen, z. in numerisch und nicht-numerisch. Und ich wollte einen Besucher schreiben, der für diese Eigenschaft einen booleschen Wert liefert. – Aleph0

+0

@FrankSimon SFINAE verwenden - eine Überladung aktiviert und eine deaktiviert, abhängig von einem Typmerkmal. – Barry

+0

Ich kenne dieses Konzept nicht. Scheint, dass ich etwas mehr über C++ lernen muss. Vielen Dank für diese tiefen Einblicke. Ich werde es mir ansehen. – Aleph0