0

I have a class that has common members but needs to be constructed in a finite number of ways based on an enumeration. 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.

3 Answers3

2

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.,

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
0

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.

Mark B
  • 95,107
  • 10
  • 109
  • 188
0

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};
};
Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • I am really looking for a template solution that fits with the legacy code (i.e. accepts `Sensor` not `Sensor` or `DerivedSensor` types) and avoids virtual methods, having to upcast or proliferating derived classes for longer enumerations. – Michael George Sep 13 '11 at 16:56
  • @Michael George, maybe I don't understand the question - you want to create `Sensor` objects but you want them to have different constructors based on the enumeration, correct? Is there something other than the constructor that depends on the enumeration? – Mark Ransom Sep 13 '11 at 17:06