使用 Visitor 对 Boost Variant 中的类型进行分类无法编译
Classify Types in Boost Variant using Visitor does not compile
我在整个项目中都在使用 boost-variant
。在一种情况下,我需要将我的 boost-variant
中包含的类型 class 化为多个 class。由于我的变体中有很多类型,所以我想到了在访问者中定义多个变体的想法。这些变体基本上是类型->class映射。
下面的代码说明了我想要实现的目标。
#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;
}
}
#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;
}
};
我在整个项目中都在使用 boost-variant
。在一种情况下,我需要将我的 boost-variant
中包含的类型 class 化为多个 class。由于我的变体中有很多类型,所以我想到了在访问者中定义多个变体的想法。这些变体基本上是类型->class映射。
下面的代码说明了我想要实现的目标。
#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;
}
}
#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;
}
};