Я использую 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;
}
}