2016-05-17 7 views
12

Ich möchte eine generische Serialisierung Bibliothek schreiben, die zum Beispiel liefert eine generische save Funktion. Die Bibliothek enthält benutzerdefinierte Typenmerkmale, z. some_condition:Extensible Typ Züge in C++

template <typename T> 
std::enable_if_t<some_condition<T>::value> save(const T& value) 
{ 
    std::cout << "these types will be handled in a specific way: " << value << std::endl; 
} 

template <typename T> 
std::enable_if_t<!some_condition<T>::value> save(const T& value) 
{ 
    std::cout << "these types will be handled in another way: " << value << std::endl; 
} 

save soll sein kundengerecht für Benutzer-Datentypen, nicht nur über Überlastung, sondern auch allgemein über Merkmale:

template <typename T> 
struct some_condition 
{ 
    constexpr static bool value = std::is_same<std::string, T>::value ||std::is_arithmetic<T>::value ; 
}; 

save ‚s Verhalten basierend auf some_condition ausgewählt. Deshalb habe ich trait_extension die für Züge Vorlagen spezialisiert werden können:

template <template<typename> class Trait, typename T> 
struct trait_extension : Trait<T> 
{ 
} 

save hat entsprechend angepasst werden:

template <typename T> 
std::enable_if_t<trait_extension<some_condition,T>::value> save(const T& value) { ... } 


template <typename T> 
std::enable_if_t<!trait_extension<some_condition,T>::value> save(const T& value) { ... } 

Ein Benutzer könnte nun liefern seine eigene Spezialisierung trait_extension:

template <typename T> 
struct trait_extension<some_condition, T> 
{ 
    // user specific extension: exclude floats from condition 
    constexpr static bool value = !std::is_floating_point<T>::value && some_condition<T>::value; 
}; 

Meine Frage ::

Gibt es eine „bessere“/elegante Art und Weise erweiterbar Züge zu realisieren?

live example

+0

Wäre es nicht einfacher sein, einen „allgemeinen Fall“ zu haben, wo is_string als falsch definiert ist, und haben Spezialisierungen definieren, was ein String betrachtet wird? – OMGtechy

+0

Haben Sie sich den [C++ Container Pretty-Printer] (https://github.com/louisdx/cxx-prettyprint) als Referenz angesehen? – ildjarn

+0

"Dies funktioniert jedoch nur, wenn die Spezialisierung' trait_extension' vor 'print' existiert." Hä? –

Antwort

1

Ich glaube nicht, Ihr Konzept überhaupt elegant ist. Es könnte sich leicht in Spaghetti-Code verwandeln und macht es schwierig zu pflegen oder zu verwenden. Ich würde stattdessen einen "Richtlinien" -basierten Ansatz verwenden, der der Klasse std::allocator in der Standardbibliothek ähnelt. Das Ändern des Verhaltens ist eine einfache Angelegenheit, die Zuweisungsschnittstelle zu implementieren und sie als einen Vorlagenparameter bereitzustellen. Dann funktioniert alles automatisch.

Für eine Sache, in einer „generic Serialisierung“ Bibliothek, müssen Sie nicht nur über die Arten kümmern, sondern auch um die Lokalisierung. Es könnte etwas so einfach sein wie , anstelle von . oder so komplex wie einheitliche Großschreibung. Mit Ihrem Ansatz, es ist nicht sehr einfach, den Strom oder locale (dh std vs Boost) Back-End zu ändern, aber mit einem richtlinienbasierte Ansatz ist es eine Frage der Suche und ersetzen:

serialize<int, std_locale<int>>(32.000) 
serialize<int, boost_locale<int>>(32.000) 

Dies erlaubt Sie zu bietet eine Reihe von „defaults“ in etwa einer Master-locale Klasse ala std::allocator, und dann kann der Benutzer nur aus, dass erbt und Verhalten für eine oder zwei Arten ändern, anstatt bietet verrückt SFINAE Überlastungen.