How to define heterogenous std::map using boost::variant in "two dimensional manner"
Asked Answered
L

1

9

I would be happy to get and advice how to deal with boost::variant in "two dimensional manner". Sounds strange but let my code say more (hopefully):

I have coded a class called Parameter:

template<typename PARAM_TYPE, typename DATA_TYPE=double>
class Parameter : public quantity<PARAM_TYPE, DATA_TYPE>
{
...
}

Example usage of my Parameter as defined above:

Parameter<si::length, double> SampleParameter1;
Parameter<si::dimensionless, short> SampleParameter2;

As I tried to explain by example above, I can define several Parameter types using the boost::units::si::??? and different data type like double, short, int etc.

My GOAL is to construct a std::map container which can store instances of any Parameter type (as sampled above).

Therefore I have declared:

typedef boost::variant<Parameter<si::dimensionless, short>, Parameter<si::length, double> > SupportedParameterTypes;
std::map<int, SupportedParameterTypes> myMapStorage;

This works pretty well but have one big disadvantage I would like to solve - I have to define every single combination of Parameter type I would like to support in SupportedParameterTypes type as defined above.

My idea was to define boost::mpl::vector constaining all the Parameter types I would like to support:

typedef boost::mpl::vector<si::dimensionless, si::length> ParameterTypes;

And all the possible Parameter data types being supported on the other hand:

typedef boost::mpl::vector<short, int, float, double> ParameterDataTypes;

There comes my troubles:

typedef typename boost::make_variant_over<ParameterTypes>::type ParameterTypeVariants;
typedef typename boost::make_variant_over<ParameterDataTypes>::type ParameterDataVariants;

typedef boost::variant<Parameter<ParameterTypeVariants, ParameterDataVariants> > SupportedParameterTypes;

But to define boost::variant of something (Parameter) which is defineed by some other boost::variant seems not to work :o(

QUESTION: How to define std::map container holding all my Parameter types defined in appropriate boost::mpl::vectors?

I would like to kindly ask you for help solving this issue. Maybe it is not good idea/principle at all to code it as I wrote, who knows. My goal is to have a flexible storage by std::map to be capable to hold all my Parameters without having my code ambiguous. Looking for smart solution of course :o)

Many thanks in advance for any reply to my question / request for help

Lucerne answered 14/12, 2015 at 9:24 Comment(2)
why two mpl vectors that separate si types and data types (making relation between them not so obvious) are better than something simple like boost::variant<Parameter<si::dimensionless, short>, Parameter<si::length, double> >?Passbook
The reason why I need the two types separated is that any parameter type can be mated with any data type. There are about 20 si:: types and about 4 data ones. That would produce huge amount of combinations I would like to avoid. Anyway, thank you for your reply!Unipersonal
H
3

You may produce all your pairing with something like

template <typename Seq, typename T1, typename T2>
struct cartesian_parameters_helper;

template <std::size_t...Is, typename T1, typename T2>
struct cartesian_parameters_helper<std::index_sequence<Is...>, T1, T2>
{
    static constexpr std::size_t size1 = std::tuple_size<T1>::value;
    using type = boost::variant<
        Parameter<
            std::tuple_element_t<Is / size1, T1>,
            std::tuple_element_t<Is % size1, T2>
            >...>;
};

template <typename T1, typename T2>
struct cartesian_parameters
{
    using type = typename cartesian_parameters_helper<
        std::make_index_sequence<std::tuple_size<T1>::value
                                 * std::tuple_size<T2>::value>,
        T1, T2>::type;
};

And then use it as

using SupportedParameterTypes =
    cartesian_parameters<std::tuple<si::dimensionless, si::length>,
                         std::tuple<short, int, float, double>>::type;

Demo

Hardie answered 14/12, 2015 at 10:40 Comment(2)
I am trying to implement my stuff using this proposal but it seems to be C++14 specific - at least I cannot find std::index_sequence<> valid for C++11. Is there any analogy existing for C++11? For example in Boost library? Many thanks in advance...Unipersonal
There are several implementation of index_sequence and make_index_sequence on SO.Hardie

© 2022 - 2024 — McMap. All rights reserved.