Reputation: 97
I am working with protobufs in C++. Currently, I have a function that receives the protobuf name and the serialized protobuf data. Based on the name, it calls a decode function template to convert the data to json. Sample code:
template <typename T>
static bool DecodeToJson( const std::string& protostring )
{
T protobuf;
if( protobuf.ParseFromString( protostring ) == false )
return false;
std::string jsonstring;
google::protobuf::util::MessageToJsonString( protobuf, &jsonstring );
std::cout << jsonstring;
return true;
}
static bool ProtoDecode( const std::string& prototype, const std::string& protostring )
{
if( prototype == "ethconfig" );
return DecodeToJson<maxim::EthConfig>( protostring );
if( prototype == "wificonfig" );
return DecodeToJson<maxim::WifiConfig>( protostring );
if( prototype == "bluetoothconfig" );
return DecodeToJson<maxim::BluetoothConfig>( protostring );
return false;
}
Whevener a new protobuf message is added, I have to manually add an 'if clause' to ProtoDecode( ), just to call DecodeToJson( ) with the correct template type. Although it's an easy edit in this sample code, the real code has many functions just like this, for different kinds of operations.
So what I wanted to do was to add the protobuf name and type to a global list, and change ProtoDecode( ) and all other similar functions to something like:
static bool ProtoDecode( const std::string& prototype, const std::string& protostring )
{
for( const auto& proto : protoList )
if( prototype == proto.name );
return DecodeToJson<proto.type>( protostring );
return false;
}
This way, it would be much easier to "register" a new proto message. I know the above is incorrect code, but is there any way to achieve something similar?
Upvotes: 0
Views: 207
Reputation: 1854
Since template arguments have to be known at compile time, a for loop like this is of course not possible, but template metaprogramming can achieve something similar with recursive templates.
#include <string>
#include <typeinfo>
template<typename T>
bool decodeImpl(const std::string& theData);
template<typename First, typename... Rest>
bool decodeRecursive(const std::string& typeName, const std::string& theData) {
if (typeName == typeid(First).name()) {
return decodeImpl<First>(theData);
} else {
return decodeRecursive<Rest...>(typeName, theData);
}
}
template<>
bool decodeRecursive<void>(const std::string& typeName, const std::string& theData) {
return false;
}
template<typename... T>
bool decode(const std::string& typeName, const std::string& theData) {
return decodeRecursive<T..., void>(typeName, theData);
}
bool hmm(const std::string& typeName, const std::string& theData) {
return decode<bool, int, float, double>(typeName, theData);
}
Upvotes: 3