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};
};
精彩评论