【问题标题】:Templated construction of non-template class非模板类的模板化构造
【发布时间】:2011-09-13 16:40:56
【问题描述】:

我有一个类,它具有共同的成员,但需要基于枚举以有限数量的方式构造。每种类型在编译时都是已知的,所以我认为模板在这里是有意义的。我知道我可以通过构造函数专业化来解决这个问题,例如:

enum SensorTypes{GPS,Radar,ShaftEncoder};

template<SensorTypes>
class Sensor
{
public:
    Sensor(unsigned char* rawdata){//Format of rawdata depends on SensorTypes};
private:
    double speed;
    double time;
}
template<> Sensor<GPS>::Sensor(unsigned char* rawdata){speed = (double)rawdata[0];}

问题是我的遗留代码必须接受 Sensor 类而不是 Sensor&lt;GPS&gt; 等。我怎样才能在保持单一类类型的同时实现类似的编译时构造。

【问题讨论】:

标签: c++ templates constructor specialization


【解决方案1】:

一开始这似乎很简单,只需在 Sensor 类中使用模板构造函数即可。

#include <stdio.h>

namespace sensorKind {
    struct GPS {};
    struct Radar {};
    struct ShaftEncoder {};
}

class Sensor
{
public:
    template< class Kind >
    Sensor( Kind, unsigned char const* rawdata );
private:
    double speed_;
    double time_;
};

template<>
Sensor::Sensor(
    sensorKind::GPS,
    unsigned char const* rawData
    )
{
    printf( "Sensor<GPS> object created.\n" );
}

template<>
Sensor::Sensor(
    sensorKind::Radar,
    unsigned char const* rawData
    )
{
    printf( "Sensor<Radar> object created.\n" );
}

int main()
{
    Sensor  aGPSSensor( sensorKind::GPS(), 0 );
    Sensor  aRadarSensor( sensorKind::Radar(), 0 );
}

但在这一点上很容易看出“类型参数”实际上是在描述原始数据,而不是其他任何东西。

所以说真的,应该输入 rawdata 参数。

使原始数据的类型更严格也可以帮助您避免错误,例如雷达原始数据被视为 GPS 原始数据。

#include <stdio.h>

namespace sensor {
    struct Kind {
        enum  Enum{ gps, radar, shaftEncoder };
    };

    template< Kind::Enum aKind >
    class DataFrom 
    {
    public:
        static Kind::Enum const kind = aKind;

        unsigned char const* ptr() const { return 0; }
        DataFrom() {}
    };
}  // namespace sensor

class Sensor
{
public:
    typedef sensor::Kind    Kind;

    template< class DataKind >
    explicit Sensor(  DataKind const& rawData );
private:
    double speed_;
    double time_;
};

template<>
Sensor::Sensor( sensor::DataFrom< Kind::gps > const& rawData )
{
    printf( "%s\n", "Sensor<GPS> object created." );
}

template<>
Sensor::Sensor( sensor::DataFrom< Kind::radar > const& rawData )
{
    printf( "%s\n", "Sensor<Radar> object created." );
}

int main()
{
    sensor::DataFrom< sensor::Kind::gps >   gpsData;
    sensor::DataFrom< sensor::Kind::radar > radarData;

    Sensor  aGPSSensor( gpsData );
    Sensor  aRadarSensor( radarData );
}

在设计方面,这是划分为 rawdata 提供者和 rawdata 解释器(Sensor 类显然是 rawdata 解释器)。

该问题暗示了该设计,但如果可能将解释知识移近数据源可能是有益的。

即,移动例如的解释雷达数据从Sensor 构造函数和类中取出,并进入携带雷达原始数据的类。

干杯,

【讨论】:

    【解决方案2】:

    根据您的具体需求,您可以创建非模板基类并派生模板特定版本,使用虚拟方法选择正确的行为。

    【讨论】:

      【解决方案3】:

      这看起来很简单,只需让您的模板类派生自现有的Sensor 类即可。

      template<SensorTypes>
      class DerivedSensor : public Sensor
      {
      public:
          DerivedSensor(unsigned char* rawdata){//Format of rawdata depends on SensorTypes};
      };
      

      【讨论】:

      • 我真的在寻找适合遗留代码的模板解决方案(即接受 Sensor 而不是 Sensor&lt;GPS&gt;DerivedSensor 类型)并避免虚拟方法,不得不向上转换或增殖派生类用于更长的枚举。
      • @Michael George,也许我不明白这个问题 - 您想创建 Sensor 对象,但您希望它们根据枚举具有不同的构造函数,对吗?除了依赖于枚举的构造函数之外还有什么东西吗?
      猜你喜欢
      • 2016-07-02
      • 1970-01-01
      • 1970-01-01
      • 2011-05-08
      • 1970-01-01
      • 2013-08-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多