Вспомогательная функция для извлечения значений из boost::variant внутри boost::any

В своих проектах я использую разные типы boost::variant. Например, у меня есть

typedef boost::variant<A1, A2> TA;
typedef boost::variant<B1, B2, B3> TB;
typedef boost::variant<A1, B2> TC;

Чтобы передать эти разные типы boost::variant через единый интерфейс, я использую boost::any. Например:

TA a=A1();
boost::any container=a;

Теперь извлечение данных A1 в данном случае из container становится немного утомительным. Я должен написать явно

A1 a=boost::get<A1>(boost::any_cast<TA>(container));

Мне просто интересно, возможно ли реализовать вспомогательную функцию шаблона следующим образом:

template<typename T>
T getValue<T>(const boost::any& any) {
 auto var=boost::any_cast</* What to put here*/>(container);
 return boost::get<T>(var);
}

Но здесь я действительно сбит с толку, какой тип писать в boost::any_cast.

Частичное решение:

После рефакторинга кода ответа на мой предыдущий вопрос я смог получить следующее частичное решение моей проблемы.

К сожалению, решение имеет еще два серьезных недостатка.

Во-первых, я не знаю, как исключить все boost::variant в Variants, которые не могут содержать запрошенный тип T.

Во-вторых, я должен явно указать список моих возможных boost::variant типов. Я считаю это ограничение не таким строгим, как первое.

#include <boost/variant.hpp>
#include <boost/any.hpp>
#include <boost/optional.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/find_if.hpp>
#include <boost/mpl/remove_if.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/joint_view.hpp>
#include <vector>
#include <iostream>

template<class T, class V>
struct variantToType
{
    variantToType(const V& value) : value(value) {  }

    boost::optional<T> result;
    V value;
    void operator()(const T& t)
    {
        if (T* val = boost::get<T>(&value)) {
            result = boost::make_optional<T>(*val);
        } else {
            result = boost::none;
        }
    }
};

template<typename T>
struct anyToVariant {
    anyToVariant(const boost::any& value) : value(value) { }

    boost::optional<T> result;
    const boost::any value;
    template<typename VARIANT>
    void operator()(const VARIANT&) {
        try {
            VARIANT var=boost::any_cast<VARIANT>(value);    

            variantToType<T, VARIANT> generator(var);
            boost::mpl::for_each<VARIANT::types>(boost::ref(generator));
            if (generator.result) {
                result = generator.result;
            }
        }
        catch (const boost::bad_any_cast&) {}
    }
};

template<class T>
boost::optional<T> convert(const boost::any&value) {
    using namespace boost; 
    anyToVariant<T> x(value);
    //using AllTypes = boost::mpl::joint_view<V1::types, V2::types>; // Of no help?

    using Variants = mpl::vector<V1, V2>::type;
    mpl::for_each<Variants>(boost::ref(x));
    return x.result;
}

typedef boost::variant<int> V1;
typedef boost::variant<double, int> V2;

int main(int argc, char**args) {
    try {
        {
            V1 x = 5;
            boost::any any = x;
            boost::optional<int> y = convert<int>(any);
            std::cout << y.value() << std::endl;
        }
        {
            V2 x = 5.5;
            boost::any any = x;

//          This will not compile due to boost::get, as V1 does not contain a double type. :-(
//          boost::optional<double> y = convert<double>(any);
//          std::cout << y.value() << std::endl;
        }
    }
    catch (const std::exception& e) {
        std::cout << e.what() << std::endl;
    }
    return 0;
}

person Aleph0    schedule 14.07.2016    source источник
comment
Я очень сомневаюсь, что это можно сделать. Что вы можете сделать, так это создать шаблон getValue как для T, так и для TA. Итак, чтобы извлечь желаемое значение, вы должны сделать getValue<A1, TA>(container).   -  person linuxfever    schedule 14.07.2016