如何返回由 boost::variant 返回类型中包含的类型的子集组成的 boost::variant
Posted
技术标签:
【中文标题】如何返回由 boost::variant 返回类型中包含的类型的子集组成的 boost::variant【英文标题】:How can I return a boost::variant made from a subset of the types contained in boost::varaint return type 【发布时间】:2017-11-09 06:28:04 【问题描述】:我有 4 个功能:
boost::variant<type1,type2,type3>processFile(const char* file)
if(----expression that if true means I have to process as type 1----)
return processType1(file); //this just returns type1
else if(----expression that if true means I have to process as either type 1 or type 2----)
return processType23(file); //this returns boost::variant<type2,type3>. This also calls 2 more processing functions depending on type.
processType23 采用一个脚本文件,该文件将确定返回的类型。我想在这个文件中保留类型的确定。但是我不能返回 boost::variant。我收到以下错误:
error: could not convert 'engine::fileManager::processLua(const char*)()' from 'boost::variant<engine::material, engine::shader>' to 'boost::variant<engine::material, engine::shader, unsigned int>'
返回数据的(正确)方式是什么?
【问题讨论】:
【参考方案1】:您应该使用访问者:
Live On Coliru
template <typename R, typename A> convert_variant(A const& arg)
return boost::apply_visitor([](auto const& v) -> R return Rv; , arg);
更新
根据@llonesmiz 的观察,您可能希望编译转换代码,即使某些转换可能是非法的。在这种情况下,您将不得不使用一些类型特征来区分这些情况并采取相应措施:
C++03 演示
Live On Coliru
#include <boost/variant.hpp>
#include <boost/type_traits.hpp>
#include <iostream>
template <typename R>
struct convert_variant_visitor : boost::static_visitor<R>
struct bad_conversion : std::runtime_error
bad_conversion(std::string msg) : std::runtime_error(msg)
;
template <typename T>
typename boost::enable_if_c<boost::is_convertible<T, R>::value, R>::type
operator()(T const& v) const
return R(v); // or just v
template <typename T>
typename boost::enable_if_c<not boost::is_convertible<T, R>::value, R>::type
operator()(T const& v) const
throw bad_conversion(std::string("Cannot convert ") + typeid(v).name() + " to " + typeid(R).name());
//throw bad_conversion("Not convertible to variant");
;
template <typename R, typename A> R convert_variant(A const& arg)
return boost::apply_visitor(convert_variant_visitor<R>(), arg);
int main()
typedef boost::variant<std::string, int, double> V1;
typedef boost::variant<int, double> V2;
V1 input = 42;
V2 output = convert_variant<V2>(input);
std::cout << "input: " << input << " (which: " << input.which() << ")\n";
std::cout << "output: " << output << " (which: " << output.which() << ")\n";
打印
input: 42 (which: 1)
output: 42 (which: 0)
C++17 演示
现代 C++ 特性使这样的通用代码变得更加简单:
Live On Coliru
template <typename R, typename A> R convert_variant(A const& arg)
return boost::apply_visitor([](auto const& v) -> R
if constexpr (std::is_convertible_v<decltype(v), R>)
return v;
else
throw std::runtime_error("bad conversion");
, arg);
【讨论】:
非常好,但我认为this(遗憾的是失败了)更接近提问者的要求。 @llonesmiz 你当然是对的。让我解决这个问题。 20 分钟后返回 @llonesmiz 我刚刚更新了答案,以便非法转换变成运行时错误。这使它在您突出显示的情况下也可以工作:coliru.stacked-crooked.com/a/e76b5be36d98c885 还有一个c++17 version 只是为了展示它可以变得多么简单 Just something to keep in mind 虽然这应该不是问题,因为if
s 的级联实际上在做他们的工作。以上是关于如何返回由 boost::variant 返回类型中包含的类型的子集组成的 boost::variant的主要内容,如果未能解决你的问题,请参考以下文章
使用 boost::variant 库制作地图。如何将事物存储和显示为正确的类型?