【问题标题】:c++ variadic template constructor initialization list of members and mixinsc++ 可变参数模板构造函数初始化成员列表和mixins
【发布时间】:2017-02-02 18:48:19
【问题描述】:

我正在尝试从我的主机类 (BaseSensor) 初始化可变数量的 mixins (ThresholdSensor<>, TrendSensor, EdgeSensor),它们也恰好需要作为构造函数参数,主机类的成员(BaseSensor::bsd)。我在这两项任务中都失败了:)

我正在使用 c++11 ,gcc 4.7.1(因此 std::map 没有“emplace”),代码如下:

#include <iostream> // std::cout std::endl
#include <string>   // std::string
#include <map>   // 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 , size_t _windowSize , const double & _trainRangefactor)
        {
            cout << "TrendSensor: " << _windowSize << " " << bsd.sensorName << " " << _trainRangefactor << endl;
        }
};

typedef struct{ double trough; double peak; } Edges;
class EdgeSensor  //mixin for BaseSensor
{
    public:
        EdgeSensor( BaseSensorData & bsd , size_t _windowSize , const double _rangeFactor)
        {
            cout << "EdgeSensor: " << _windowSize << " " << bsd.sensorName << " " << _rangeFactor << endl;
        }
};

class CO2Threshold //mixin for ThresholdSensor
{
    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 //mixin for ThresholdSensor
{
    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
                        , const size_t & _windowSize
                        , const double & _toxicThres)
            : ThresholdMixin
                ( _toxicThres //3x the same arg
                , _toxicThres //just for the sake
                , _toxicThres //of this exercise
                )
        {
            cout << "ThresholdSensor: " << _windowSize << " " << bsd.sensorName << " " << endl;
        }

};

template<typename ... SensorType>
class BaseSensor : public SensorType ... //to my BaseSensor class
{
    BaseSensorData bsd;

    public:
        BaseSensor(const string& _sensorName , size_t _windowSize , const double d)
            :
            bsd(_sensorName) //this causes "Wreorder" warning. 
            ,
            SensorType( bsd , _windowSize , d )...
        {
            cout << "BaseSensor: " << _windowSize << " " << bsd.sensorName << " " << endl;
        }

};

int main() {
    BaseSensor<ThresholdSensor<CO2Threshold> , TrendSensor, EdgeSensor> bs{string("test"),60U , 14.5f};
    //BaseSensor<EdgeSensor> bs2;
}

专注于 BaseSensor ,我使用 gdb 运行可执行文件,我意识到没有办法让“bsd”成员首先初始化。 “SensorType” mixins 将首先被初始化。那么如何先初始化bsd呢?

其次,通过一步一步的执行,我意识到执行只进入“ThresholdSensor”,而不是“TrendSensor”或“EdgeSensor”。这是为什么?我虽然所有的 mixins 都将使用省略号语法进行评估。 initializer_list 会以某种方式帮助 init 排序吗?如果我包含以下信息,initializer_list 是否仍然是建议的解决方案

提前感谢您的帮助

【问题讨论】:

    标签: c++ c++11 constructor initialization variadic-templates


    【解决方案1】:

    我不太喜欢下面的解决方案,但是...

    首先:您可以修改SensorType 类以接收(作为构造函数的第一个参数)指向BaseSensorData指针,而不是引用;例如,TendSensor 变为

    class TrendSensor //mixin for BaseSensor
     {
       public:
          TrendSensor (BaseSensorData * pBsd, size_t _windowSize,
                       const double & _trainRangefactor)
           { std::cout << "TrendSensor: " << _windowSize << " "
                << pBsd->sensorName << " " << _trainRangefactor << std::endl; }
     };
    

    第二:可以修改BaseSensor派生自BaseSensorData(重要:在SensorType...包之前)并删除bsd成员; BaseSensor成为

    template <typename ... SensorType>
    class BaseSensor : public BaseSensorData, public SensorType ...
     {
       public:
    
          BaseSensor (const std::string & _sensorName, size_t _windowSize,
                      const double d)
             : BaseSensorData(_sensorName), SensorType(this, _windowSize, d )...
                { std::cout << "BaseSensor: " << _windowSize << " "
                  << sensorName << " " << std::endl; } 
     };
    

    完整的例子如下

    #include <iostream> // std::cout std::endl
    #include <string>   // std::string
    #include <map>      // std::map
    
    struct BaseSensorData
     {
       BaseSensorData (const std::string & _sensorName)
          : sensorName(_sensorName)
        {}
    
       const std::string sensorName;
     };
    
    class TrendSensor //mixin for BaseSensor
     {
       public:
          TrendSensor (BaseSensorData * pBsd, size_t _windowSize,
                       const double & _trainRangefactor)
           { std::cout << "TrendSensor: " << _windowSize << " "
                << pBsd->sensorName << " " << _trainRangefactor << std::endl; }
     };
    
    typedef struct { double trough; double peak; } Edges;
    
    class EdgeSensor  //mixin for BaseSensor
     {
       public:
          EdgeSensor (BaseSensorData * pBsd, size_t _windowSize,
                      const double _rangeFactor)
           { std::cout << "EdgeSensor: " << _windowSize << " "
                << pBsd->sensorName << " " << _rangeFactor << std::endl; }
     };
    
    class CO2Threshold //mixin for ThresholdSensor
     {
       private:
          std::map<std::string, double> thresholds;
    
       public:
          CO2Threshold (const double & _toxicThres, const double & _zeroThres,
                        const double & )
           {
             thresholds["toxic"] = _toxicThres;
             thresholds["zero"] = _zeroThres;
             std::cout << "CO2Threshold: " << _toxicThres << " "
                << thresholds["zero"] << std::endl;
           }
    };
    
    class O2Threshold //mixin for ThresholdSensor
     {
       private:
    
          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;
             std::cout << "O2Threshold: " << _toxicThres << " "
                << thresholds["low"] << " " << thresholds["elecchem"]
                << std::endl;
           }
     };
    
    template <typename ThresholdMixin> //CO2Threshold , O2Threshold , or others ...
    class ThresholdSensor : public ThresholdMixin  //mixin for BaseSensor
     {
       public:
          ThresholdSensor (BaseSensorData * pBsd, const size_t & _windowSize,
                           const double & _toxicThres)
             : ThresholdMixin
                ( _toxicThres, //3x the same arg
                  _toxicThres, //just for the sake
                  _toxicThres)  //of this exercise
           { std::cout << "ThresholdSensor: " << _windowSize << " "
             << pBsd->sensorName << " " << std::endl; }
     };
    
    template <typename ... SensorType>
    class BaseSensor : public BaseSensorData, public SensorType ...
     {
       public:
    
          BaseSensor (const std::string & _sensorName, size_t _windowSize,
                      const double d)
             : BaseSensorData(_sensorName), SensorType(this, _windowSize, d )...
                { std::cout << "BaseSensor: " << _windowSize << " "
                  << sensorName << " " << std::endl; } 
     };
    
    int main()
     {
       BaseSensor<ThresholdSensor<CO2Threshold>,
          TrendSensor, EdgeSensor> bs { std::string("test"), 60U, 14.5f };
    
       //BaseSensor<EdgeSensor> bs2;
     }
    

    【讨论】:

    • 您对这个解决方案有什么特别不喜欢的地方?
    • @nass - 我想这是个人品味的问题,但是......我更喜欢使用对对象的引用而不是指向对象的指针,如果可能的话
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-14
    • 1970-01-01
    • 1970-01-01
    • 2016-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多