开发者

Templated construction of non-template class

I have a class that has common members but needs to be constructed in a finite number of ways based on an en开发者_开发百科umeration. Each type is known at compile time, so I am thinking templates make sense here. I know I can solve this with constructor specialization, e.g.:

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];}

The problem is I have legacy code which must accept Sensor classes not Sensor<GPS> etc. How can I achieve similar compile time construction while maintaining a single class type.


This seems simple enough at first, just use a templated constructor in the Sensor class.

#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 );
}

But at this point it's easy to see that the "type-argument" is really describing the rawdata, and nothing else.

So really, it should be the rawdata argument that should be typed.

Making the rawdata more strictly typed also helps you avoid foul-ups were e.g. radar rawdata is treated as GPS rawdata.

#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 );
}

Design-wise, this is partitioning into rawdata providers and rawdata interpreters (the Sensor class is evidently a rawdata interpreter).

That design is implied by the question, but if may be that it could be beneficial to move the interpretation knowledge closer to the data sources.

I.e., to move the interpretation of e.g. radar data out of the Sensor constructor and class, and into the class carrying radar rawdata.

Cheers & hth.,


Depending on your specific needs, you may be able to create a non-template base class and derive the template-specific version, using virtual methods to select the right behavior.


This seems simple enough, just have your template class derive from the existing Sensor class.

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜