首页 > 解决方案 > C++ 根据参数类型自动选择正确的重载函数

问题描述

我正在创建一个OutputItem<T>用于写入 json 对象的接口。我希望有不同的写入 json 对象的模式,因此我提供了一个重载方法json_serialize,它接受一个SetConstructType*orAppendConstructType*参数,它们是ConstructType. 在构造 时OutputItem<T>,我希望用户在构造函数中传递 a ConstructType*,该构造函数OutputItem<T>将被保存以const ConstructType* constructType供以后在调用公共方法时自动选择正确的重载类型void write(nlohmann::json& json)

但是我收到一个错误:

'void OutputItem::json_serialize(const SetConstructType *,nlohmann::json &)':无法将参数 1 从 'const ConstructType *' 转换为 'const SetConstructType *'

有人可以告诉我实现这种自动重载解决方案的正确方法吗?此外,这是 SFINAE 设计的一个例子吗?

谢谢

struct ConstructType {

protected:
    ConstructType() {}
};
struct SetConstructType : public ConstructType {};
struct AppendConstructType : public ConstructType {};

static SetConstructType*  SetConstruct;
static AppendConstructType*  AppendConstruct;

template<typename T>
struct OutputItem {

    OutputItem(const std::string& cgroupName, const std::string& citemName, const T& cdata, ConstructType* cconstructType) 
: itemName(citemName), groupName(cgroupName), data(cdata), constructType(cconstructType) {}
    
    const std::string itemName;
    const std::string groupName;
    const T data;

    const ConstructType* constructType;

    void write(nlohmann::json& json) {
        json_serialize(constructType, json);
    }

private:

    void json_serialize(const SetConstructType*, nlohmann::json& json) {
        json[groupName][itemName] = data;
    }

    void json_serialize(const AppendConstructType*, nlohmann::json& json) {
        json[groupName][itemName].push_back(data);
    }
};

用法

    json response;

    OutputItem<int> item1("testgroup", "item1", 2, AppendConstruct);
    OutputItem<int> item2("testgroup", "item2", 2, SetConstruct);
    item1.write(response);
    item2.write(response);

标签: c++overloadingsfinaeoverload-resolution

解决方案


由于您无法在运行时选择重载,因此您需要一种更动态的机制。
由于您不能拥有虚拟模板,因此很难用您的外部层次结构解决这个问题。

一种替代方法是通过成员函数指针重定向。

插图(没有您的所有参数和数据):

enum class Construction
{
    Set,
    Append
};

template<typename T>
class OutputItem {
public:
    OutputItem(Construction kind): construct(select(kind)) {}
    void write() { (this->*construct)(); }

private:
    using ConstructType = void (OutputItem::*)();
    ConstructType construct;
    
    ConstructType select(Construction c)
    {
        static ConstructType cs[] = { &OutputItem::setConstruct, 
                                      &OutputItem::appendConstruct };
        return cs[static_cast<int>(c)];
    }
    void setConstruct() { std::cout << "Set\n"; }
    void appendConstruct() { std::cout << "Append\n"; }
};

//...
int main()
{
    OutputItem<int> o0(Construction::Set);
    o0.write();
    OutputItem<std::string> o1(Construction::Append);
    o1.write();
}


推荐阅读