将 boost::any 转换为 boost::variant 的通用函数
Generic function to convert boost::any to boost::variant
假设您有一个boost::any
对象和一个boost::variant
对象。
我正在寻找一个通用函数convert
,它采用模板参数 T 作为专用boost::variant
例如 boost::variant<int, std::string>
并神奇地将boost::any
转换为给定boost::variant
的可用类型之一。
template<T>
T convert(const boost::any& any) {
// Some generic conversion code here or throw exception if conversion is not possible!
}
int main(int argc, char** args) {
typedef boost::variant<int, std::string> TVar;
boost::any any="Hello World";
TVar variant=convert<TVar>(any);
// variant contains "Hello World"
return 0;
}
我想知道是否有可能编写这样的函数,或者由于某种原因可能是不可能的?
让我们将所有代码包含在按变量类型模板化的结构中
template<class VAR>
struct ExtractorGenerator
{
using Extractor = std::function<boost::optional<VAR>(boost::any const &)>;
std::vector<Extractor> extractors;
template<class T>
static boost::optional<VAR> tryCast(boost::any const & arg);
template<class T>
void operator()(T);
};
您可以轻松编写一个函数,对于给定类型,尝试将 boost::any 转换为此类型的变体
template<class VAR>
template<class T>
boost::optional<VAR> ExtractorGenerator<VAR>::tryCast(boost::any const & arg)
{
T const * val = boost::any_cast<T>(&arg);
return val == nullptr ? boost::none : boost::make_optional(VAR{*val});
}
现在使用 boost::mpl,您可以遍历所有变体类型,为每个变体的类型生成函数
template<class VAR>
template<class T> void ExtractorGenerator<VAR>::operator()(T)
{
extractors.push_back(Extractor::tryCast<T>);
}
typedef boost::variant<int, std::string, char> MyVariant;
ExtractorGenerator<MyVariant> generator;
boost::mpl::for_each<MyVariant::types>(boost::ref(generator));
现在您只需应用所有创建的函数:
std::vector<MyVariant> extractedVals;
for (auto fun : extractor.extractors)
{
boost::optional<MyVariant> extracted = fun(val);
if (extracted)
extractedVals.push_back(extracted.get());
}
您可以为boost::variant
中的每个类型调用boost::any_cast
,并在第一次强制转换成功时停止:
#include <iostream>
#include <utility>
#include <stdexcept>
#include <sstream>
#include <boost/any.hpp>
#include <boost/variant.hpp>
#include <boost/type_index.hpp>
#include <boost/mpl/size.hpp>
#include <boost/mpl/at.hpp>
template <typename Sequence>
struct mpl_sequence_to_std_tuple
{
template <std::size_t... Is>
static auto x(std::index_sequence<Is...>) -> std::tuple<typename boost::mpl::at_c<Sequence, Is>::type...>;
using type = decltype(x(std::make_index_sequence<boost::mpl::size<Sequence>::type::value>{}));
};
struct signal_conversion_success{};
template <typename T, typename Variant>
void try_convert(const boost::any& any, Variant& var)
{
try
{
var = boost::any_cast<T>(any);
throw signal_conversion_success{};
}
catch(const boost::bad_any_cast &)
{
}
}
template <typename T, typename... Ts>
std::string parameter_pack_to_string(const std::string& separator = ", ")
{
std::stringstream ss;
ss << boost::typeindex::type_id<T>().pretty_name();
auto l = {0, (void(ss << separator << boost::typeindex::type_id<Ts>().pretty_name()),0)...};
std::ignore = l;
return ss.str();
}
template <typename Variant, typename...Ts>
void do_convert(const boost::any& any, Variant& var, std::tuple<Ts...>)
{
bool success = false;
try {
auto l = {0, (void(try_convert<Ts>(any, var)), 0)... };
std::ignore = l;
}
catch(const signal_conversion_success&)
{
success = true;
}
if (!success)
{
std::stringstream ss;
ss << "cannot convert this boost::any instance to any of the following types: ";
ss << parameter_pack_to_string<Ts...>();
throw std::invalid_argument(ss.str());
}
}
template<typename Variant>
void convert(const boost::any& any, Variant& var)
{
using Tuple = typename mpl_sequence_to_std_tuple<typename Variant::types>::type;
do_convert(any, var, Tuple{});
}
struct print_visitor : public boost::static_visitor<void>
{
template <typename T>
void operator()(T&& t) const
{
std::cout << boost::typeindex::type_id<T>().pretty_name() << ": " << std::forward<T>(t) << std::endl;
}
};
int main()
{
using Variant = boost::variant<int, std::string>;
boost::any any = std::string("Hello World");
Variant var;
convert(any, var);
boost::apply_visitor(print_visitor(), var);
}
现场示例
如果所有强制转换均未成功,则会引发异常,请参阅以下实时示例。
相关文章:
- 我正在将一个 std::string 传递给一个 boost 函数,该函数对该类型进行常量引用,但该值发生了变化
- 如何将Boost ::函数对象与所有参数绑定
- 从boost ::函数中提取参数
- Boost绑定和Boost函数,将带有参数的函数存储在向量中,然后执行它们
- 如何获得返回自身的boost::函数(或其他通用函数包装器)
- Boost函数赋值引发异常
- 正在从带有参数的new_ptr的boost::lambda::bind中获取boost::函数
- boost::函数与函数指针
- boost::函数参数定义不起作用
- 将boost::函数克隆到指针中,并用该指针调用封装的函数
- 使用boost::函数绑定到重载方法
- 如何使用boost函数来转换参数类型
- Boost::函数绑定的成员函数无效
- boost::函数与函数模板
- 如何将两个独立的boost::bind()组合为一个boost::函数
- boost元组导致boost绑定/boost函数出现问题
- 为什么某些 Boost 函数不需要以命名空间为前缀
- 从函数指针创建boost::函数的跨平台方法
- 传递boost::函数,该函数接受一个模板实参作为默认为NULL的形参
- 对模板使用boost::函数