I know the title is not meaningful, couldn't find anything better.
I need to provide a C++ interface to an SQlite table, where I can store key/value/type configuration settings, such as
Key | Value | Type
PATH | /path/to/ | STRING
HAS_FEATURE | Y | BOOLEAN
REFRESH_RATE| 60 | INTEGER
For simplicity and flexibility purposes the datamodel hosts the values as strings but provides a column to retain the original data type.
This is how I have imagined a client to call such c++ interface.
Configuration c;
int refreshRate = c.get<int>("REFRESH_RATE");
// Next line throws since type won't match
std::string refreshRate = c.get<std::string>("REFRESH_RATE");
This is how I have imagined implementing it (I know the code won't compile as is, consider it as pseudo c++, I'm more questioning the design than the syntax here)
class Parameter
{
public:
enum KnownTypes
{
STRING = 0,
BOOLEAN,
INTEGER,
DOUBLE,
...
}
std::string key;
std::string value;
KnownTypes type;
}
class Configuration
{
public:
template<class RETURNTYPE>
RETURNTYPE get(std::string& key)
{
// get parameter(eg. get cached value or from db...)
const Parameter& parameter = retrieveFromDbOrCache(key);
return <parameter.type, RETURNTYPE>getImpl(parameter);
}
private:
template<int ENUMTYPE, class RETURNTYPE>
RETURNTYPE getImpl(const Parameter& parameter)
{
throw "Tthe requested return type does not match with the actual parameter's type"; // shall never happen
}
template<Parameter::KnownTypes::STRING, std::string>
std::string getImpl(const Parameter& parameter)
{
return parameter.value;
}
template<Parameter::KnownTypes::BOOLEAN, bool>
std::string getImpl(const Parameter& parameter)
{
return parameter.value == "Y";
}
template<Parameter::KnownTypes::INTEGER, int>
int getImpl(const Parameter& parameter)
{
return lexical_cast<int>(parameter.value)
}
// and so on, specialize once per known type
};
Is that a good implementation ? Any suggestions on how to improve it ?
I know I could have specialized the public get
directly per return type, but I would have duplicated some code in each template specialization (the type consistency check as well as the parameter retrieval)
Your approach will fail badly if you try to implement it out! Problem is:
or with correct C++ syntax:
Template parameters require to be compile time constants, which
parameter.type
is not! So you would have to try something like this:Does not look like you gained anything at all, does it?
You might try the other way round, though, specialising the getter itself:
Or without templates (referring Nim's comment...):
One change you might have noticed: I fixed constness for your parameters...
Side note: template specialisations as above are not allowed at class scope (above is written for shortness). In your true code, you have to move the specialisations out of the class: