c++ - 从表中检索混合数据类型的模板化 get 方法

标签 c++ templates boost type-erasure lexical-cast

我知道标题没有意义,找不到更好的。

我需要为 SQlite 表提供一个 C++ 接口(interface),我可以在其中存储键/值/类型配置设置,例如

    Key     |   Value    |   Type
PATH        | /path/to/  |  STRING
HAS_FEATURE |    Y       |  BOOLEAN
REFRESH_RATE|    60      |  INTEGER

出于简单性和灵 active 的目的,数据模型将值托管为字符串,但提供一列以保留原始数据类型。

这就是我想象的客户端调用这样的 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");

这就是我想象中的实现方式(我知道代码不会按原样编译,将其视为伪 C++,我对设计的质疑多于此处的语法)

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

这是一个很好的实现吗?关于如何改进它有什么建议吗?

我知道我可以根据返回类型直接特化 public get,但我会在每个模板特化中复制一些代码(类型一致性检查以及参数检索)

最佳答案

如果您尝试实现您的方法,您的方法将严重失败!问题是:

return <parameter.type, RETURNTYPE>getImpl(parameter);

或使用正确的 C++ 语法:

return getImpl<parameter.type, RETURNTYPE>(parameter);

模板参数要求是编译时常量,parameter.type 不是!所以你必须尝试这样的事情:

switch(parameter.type)
{
case STRING:
    return getImpl<STRING, RETURNTYPE>(parameter);
//...
}

看起来你一点收获都没有,是吗?

不过,您可以尝试相反的方法,专门化 getter 本身:

public:
    template<class RETURNTYPE>
    RETURNTYPE get(std::string const& key);

    template<>
    std::string get<std::string>(std::string const& key)
    {
        return getImpl<STRING>(key);
    }
    template<>
    int get<int>(std::string const& key)
    {
        return lexical_cast<int>(getImpl<STRING>(key));
    }

private:
    template<KnownTypes Type>
    std::string getImpl(std::string const& key)
    {
        Parameter parameter = ...;
        if(parameter.type != Type)
            throw ...;
        return parameter.value;
    }

或者没有模板(引用 Nim 的评论...):

public:
    int getInt(std::string const& key)
    {
        return lexical_cast<int>(getImpl(STRING, key));
    }

private:
    inline std::string getImpl(KnownTypes type, std::string const& key)
    {
        Parameter parameter = ...;
        if(parameter.type != type)
            throw ...;
        return parameter.value;
    }

您可能已经注意到了一个变化:我修复了您参数的常量性...

旁注:在类范围内不允许使用上述模板特化(以上内容是为了简短起见)。在您的真实代码中,您必须将特化移出类(class):

struct S { template<typename T> void f(T t); };

template<> void S::f<int>(int t) { }

关于c++ - 从表中检索混合数据类型的模板化 get 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44261474/

相关文章:

c++ - boost asio 给予您必须将 -D__USE_W32_SOCKETS 添加到 cygwin 上的编译器选项

c++ - C++中的C代码不兼容参数错误

c++ - ANTLR - 保持 block 不变

c++ - 我不知道如何填充数组

Django 模板 - 我可以设置要在父模板中使用的变量吗?

c++ - 使用 boost 序列化为二进制存档。输入流错误

c++ - 传递对对象的引用以进行变异 C++

c++ - C2084 - 函数已经有主体

c++ - SFINAE 尝试使用 bool 给出编译器错误 : "template argument ‘T::value’ involves template parameter"

c++ - 创建 boost 工具可执行文件