成员和mixin的c++可变参数模板构造函数初始化列表

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

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

我使用的是 c++11、gcc 4.7.1(因此 std::map 没有“位置”),代码如下:

#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”mixin 将首先初始化。那么我怎样才能先初始化 bsd?

其次,通过逐步执行,我意识到执行仅进入“ThresholdSensor”,而不会进入“TrendSensor”或“EdgeSensor”。这是为什么?我虽然所有 mixin 都将使用省略号语法进行评估。会 initializer_list以某种方式帮助初始化排序?会 initializer_list如果我包含最终 BaseSensor mixin 将具有不同数量(和类型)的参数并且每个 mixin 将需要这些参数的不同值的信息,仍然是建议的解决方案..?

预先感谢您的帮助

最佳答案

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

首先:您可以修改 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; }
 };

其次:您可以修改从 BaseSensorData 派生的 BaseSensor(重要:在 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;
 }

关于成员和mixin的c++可变参数模板构造函数初始化列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39685665/

相关文章:

c++ - 将派生类视为基类 - 它如何帮助我们避免编写更多代码?

c++ - 在工作线程创建新 GUI 元素的地方使用 Qt

c++ - 创建一个变量来保存不同类型的对象 C++

c++ - GCC c++11 使用大量带有 STL 位集 <UINT_MAX> 的 RAM

c++ - atomic() 中的++、add 操作和 fetch_add() 有什么区别

c++ - 没有匹配函数调用 "standard constructor"

c++ - 在双重继承的情况下如何处理非标准构造函数

c++ - DeferWindowPos 奇怪的行为

c++ - 构建父级的可变参数模板构造函数

c#:初学者CLASS构造函数问题