J'utilise boost-variant
dans mes projets. Dans un scénario, j'ai besoin de classer les types contenus dans mon boost-variant
en plusieurs classes. Comme j'ai beaucoup de types dans ma variante, je suis venu à l'idée de définir plusieurs variantes à l'intérieur de mon visiteur. Ces variantes sont essentiellement le mappage type-> classe.Classifier les types dans Boost Variante en utilisant Visitor ne compile pas
Le code ci-dessous illustre ce que je voulais réaliser.
#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);
}
Malheureusement, le code ne sera pas compilé. MSVC se termine par l'erreur de compilation C3066
. Il existe différentes possibilités d'appeler un objet de ce type avec ces arguments? Ce peut être l'une des trois fonctions operator()
.
Mais fondamentalement, je ne peux convertir 5 que vers le type de variante IntegerTypes
.
Quelle pourrait être la solution pour ce genre de problème?
Solution propre
Après avoir essayé d'utiliser boost-mpl
je suis arrivé à cette solution. La fonction Contains
représente un morceau de logiciel réutilisable, qui pourrait être inclus dans d'autres parties de mon programme. Je souhaitais néanmoins que la solution soit plus proche de mon code source original.
#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;
}
}
cool. J'ai également dérivé cette solution maintenant. Cela semble être la seule approche réalisable. Mais lire cela pourrait vous faire mal à la tête. :-) Je posterai aussi ma solution. Merci beaucoup. – Aleph0
@FrankSimon plus d'alternatives incluent: tag-dispatching et en ajoutant une surcharge distincte pour chaque type –
Aucune idée de ce tag-dispatching est. Je pense que je dois apprendre un peu plus. :-) – Aleph0