nass
nass

Reputation: 1485

how to unpack a set of tuples passed in a mixins Host class (which ultimately are fowarded to the mixins)

I have the following code which works fine in forwarding various std::tuples to the various mixins of my "BaseSensor" host class.

#include <iostream> // std::cout std::endl
#include <string>   // std::string
#include <map>   // std::map
#include <tuple>   // std::map

using namespace std;

struct BaseSensorData
{
    BaseSensorData(const string & _sensorName)
        : sensorName(_sensorName)
    {}

    const string sensorName;
};

class TrendSensor //mixin for BaseSensor
{
    public:
        TrendSensor( BaseSensorData * bsd , std::tuple<size_t , double > && tp)
        {
            cout << "TrendSensor: " << std::get<0>(tp) << " " << bsd->sensorName << " " << std::get<1>(tp) << endl;
        }
};

typedef struct{ double trough; double peak; } Edges;
class EdgeSensor  //mixin for BaseSensor
{
    public:
        EdgeSensor( BaseSensorData * bsd , std::tuple<size_t , double > && tp)
        {
            cout << "EdgeSensor: " << std::get<0>(tp) << " " << bsd->sensorName << " " << std::get<1>(tp) << endl;
        }
};

class CO2Threshold// : public ThresholdData
{
    std::map<std::string , double>thresholds;

    public:
        CO2Threshold( const double & _toxicThres , const double & _zeroThres , const double & )
        {
            thresholds["toxic"] = _toxicThres;
            thresholds["zero"] = _zeroThres;
            cout << "CO2Threshold: " << _toxicThres << " " << thresholds["zero"] << endl;
        }
};
class O2Threshold// : public ThresholdData
{
    std::map<std::string , double>thresholds;

    public:
        O2Threshold( const double & _toxicThres , const double & _lowThres , const double & _elecChemThres )
        {
            thresholds["toxic"] = _toxicThres;
            thresholds["low"] = _lowThres;
            thresholds["elecchem"] = _elecChemThres;
            cout << "O2Threshold: " << _toxicThres << " " << thresholds["low"] << " " << thresholds["elecchem"] << endl;
        }
};

template<typename ThresholdMixin> //CO2Threshold , O2Threshold , or others ...
class ThresholdSensor : public ThresholdMixin  //mixin for BaseSensor
{
    public:
        ThresholdSensor ( BaseSensorData * bsd
                        , std::tuple<size_t , double , double , double , double> && tp)
            : ThresholdMixin
                ( std::get<2>(tp)
                , std::get<3>(tp)
                , std::get<4>(tp)
                )
        {
            cout << "ThresholdSensor: " << std::get<0>(tp) << " " << bsd->sensorName << " "
                 <<  std::get<1>(tp) << " " << std::get<2>(tp) << " " << std::get<3>(tp) << " " << std::get<4>(tp)
                 << endl;
        }

};

template<typename ... SensorType>
class BaseSensor : public BaseSensorData , public SensorType ... //to my BaseSensor class
{
    size_t windowSize;
    public:
        template<typename ... Args>
        BaseSensor(const string& _sensorName , Args && ... args)
            : BaseSensorData(_sensorName)
            , SensorType( this , std::forward<Args>(args) )...
            , windowSize(0U)
        {
            std::tuple<Args...> arr[sizeof...(SensorType)] = { args ... }; //line A
            /*for (size_t i = 0; i < sizeof...(SensorType); ++i)
            {
                for (size_t i = 0; i < sizeof...(Args); ++i)
                {
                    // do stuff
                }
            }*/
            cout << "BaseSensor: " << /*_windowSize << " " << */sensorName << " " << endl;
        }

};

int main() {
    BaseSensor<ThresholdSensor<O2Threshold> , TrendSensor, EdgeSensor>bs
    {
        string("testSensor")
        , std::make_tuple<size_t , double , double , double , double>( 54U , 2.5f , 10000.3f , 400.5f , 200.3f )
        , std::make_tuple<size_t , double >( 53U , 6.5f )
        , std::make_tuple<size_t , double >( 52U , 3.5f )
    };

    /*BaseSensor<ThresholdSensor<CO2Threshold> , TrendSensor, EdgeSensor>bs5
    {
        string("testSensor")
        , std::make_tuple<size_t , double , double , double , double>( 54U , 2.5f , 10000.3f , 400.5f , 200.3f )
        , std::make_tuple<size_t , double >( 53U , 6.5f )
        , std::make_tuple<size_t , double >( 52U , 3.5f )
    };*/
    //BaseSensor<ThresholdSensor<CO2Threshold> > bs2{string("test"),11U , 12.5f};
    //BaseSensor<TrendSensor> bs3{string("test"), 8U , 10.5f};
    //BaseSensor<EdgeSensor> bs4{string("test"), 6U , 18.5f};

}

So in "BaseSensor" the tuples of all mixins (ie the "SensorTypes ...") are forwarded through the "Args ..." parameter pack. This works fine but I need in the BaseSensor::BaseSensor() body to get access to those tuples. The syntax for doing that however eludes me.

how can I expand at the same time SensorType ... and Args ... and categorize the "args" according to tuple? With the code above, I get the following in g++ v4.7.1 and c++11 enabled:

varcon.cpp:104:64: error: could not convert ‘args#0’ from ‘std::tuple<long unsigned int, double, double, double, double>’ to ‘std::tuple<std::tuple<long unsigned int, double, double, double, double>, std::tuple<long unsigned int, double>, std::tuple<long unsigned int, double> >’
varcon.cpp:104:64: error: could not convert ‘args#1’ from ‘std::tuple<long unsigned int, double>’ to ‘std::tuple<std::tuple<long unsigned int, double, double, double, double>, std::tuple<long unsigned int, double>, std::tuple<long unsigned int, double> >’
varcon.cpp:104:64: error: could not convert ‘args#2’ from ‘std::tuple<long unsigned int, double>’ to ‘std::tuple<std::tuple<long unsigned int, double, double, double, double>, std::tuple<long unsigned int, double>, std::tuple<long unsigned int, double> >’
varcon.cpp:108:59: error: incomplete type ‘std::tuple_size<std::tuple<std::tuple<long unsigned int, double, double, double, double>, std::tuple<long unsigned int, double>, std::tuple<long unsigned int, double> >&>’ used in nested name specifier

Upvotes: 0

Views: 75

Answers (1)

max66
max66

Reputation: 66200

What do you want obtain with the following instruction?

std::tuple<Args...> arr[sizeof...(SensorType)] = { args ... };

The Args... pack is a path of differents std::tuple types; so your arr is an array of tuples of tuples; so you have to feed it with a sequence of tuples of tuples. But the args... pack it's only a pack of tuples, not tuples of tuples.

So the error from my clang++

tmp_002-11,14,gcc,clang.cpp:93:64: error: no viable conversion from
      'tuple<unsigned long, double, double, double, double>' to
      'tuple<std::tuple<unsigned long, double, double, double, double>,
      std::tuple<unsigned long, double>, std::tuple<unsigned long, double>,
      (no argument), (no argument)>'

I suppose you could throw away the array part and define arr as

std::tuple<Args...> arr { args ... }; 

Next, if you want to access to the single elements, you could write something like

std::get<0>(std::get<1>(arr));

where the first std::get (the internal one) access to a tuple (one of the args...) and the second std::get (the more external) access to an element of the tuple (size_t or double).

Upvotes: 1

Related Questions