如何创建类类型列表,以便通过迭代重复调用模板函数?

问题描述

我正在使用 C++ 中的 protobufs。目前,我有一个接收 protobuf 名称和序列化的 protobuf 数据的函数。根据名称,它调用解码函数模板将数据转换为json。示例代码

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

无论添加了新的 protobuf 消息,我都必须手动向 ProtoDecode() 添加“if 子句”,以便使用正确的模板类型调用 DecodetoJson()。虽然这个示例代码很容易编辑,但真正的代码有很多这样的功能,用于不同类型的操作。

所以我想做的是将 protobuf 名称和类型添加到全局列表中,并将 ProtoDecode( ) 和所有其他类似函数更改为:

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

这样,“注册”新的原始消息会容易得多。我知道上面的代码不正确,但是有什么方法可以实现类似的功能吗?

解决方法

由于模板参数必须在编译时就知道,像这样的 for 循环当然是不可能的,但是模板元编程可以实现与递归模板类似的东西。

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