如何返回由boost :: varaint返回类型中包含的类型子集构成的boost :: variant

时间:2017-11-09 06:28:05

标签: c++ boost variant boost-variant

我有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 个答案:

答案 0 :(得分:1)

你应该使用访客:

<强> Live On Coliru

template <typename R, typename A> convert_variant(A const& arg) {
    return boost::apply_visitor([](auto const& v) -> R { return R{v}; }, arg);
}

更新

响应@llonesmiz的观察,您可能希望编译转换代码,即使某些转换可能是非法的。在这种情况下,您将不得不使用某些类型特征来执行这些案例并采取相应行动:

C ++ 03 Demo

<强> 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 Demo

现代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);
}