C++ 如何根据参数类型自动选择重载函数及是否属于SFINAE设计
问题原因
C++的函数重载决议发生在编译阶段,你当前将构造类型指针存储为基类const ConstructType*类型,编译期无法感知其实际指向的派生类类型,因此无法匹配到接收派生类指针的json_serialize重载,直接触发类型转换报错。
正确实现方案
这里给出两种常用的实现思路,优先推荐第一种编译期确定类型的方案,无运行时开销性能更高:
方案1:将构造类型作为OutputItem的模板参数
直接在编译期把构造类型固化到OutputItem的类型中,不需要额外存储类型指针,重载可以直接匹配:
#include <nlohmann/json.hpp> using json = nlohmann::json; struct ConstructType { protected: ConstructType() {} }; struct SetConstructType : public ConstructType {}; struct AppendConstructType : public ConstructType {}; // 全局实例直接用常量对象,避免空指针风险 inline constexpr SetConstructType SetConstruct{}; inline constexpr AppendConstructType AppendConstruct{}; // 新增ConstructType模板参数 template<typename T, typename ConstructT> struct OutputItem { OutputItem(const std::string& cgroupName, const std::string& citemName, const T& cdata, const ConstructT&) : itemName(citemName), groupName(cgroupName), data(cdata) {} const std::string itemName; const std::string groupName; const T data; void write(nlohmann::json& json) { json_serialize(static_cast<const ConstructT*>(nullptr), 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); } }; // C++17及以上可加推导指引,不需要手动写模板参数 template<typename T, typename ConstructT> OutputItem(const std::string&, const std::string&, const T&, const ConstructT&) -> OutputItem<T, ConstructT>;
使用方式和你原有写法完全一致:
json response; OutputItem item1("testgroup", "item1", 2, AppendConstruct); OutputItem item2("testgroup", "item2", 2, SetConstruct); item1.write(response); item2.write(response);
如果使用C++17以下版本不支持类模板参数推导,手动指定模板参数即可:OutputItem<int, AppendConstructType> item1(...)。
方案2:运行时类型判断
如果你确实需要运行时动态切换构造类型,可以在调用序列化前做类型转换判断,需要先给基类添加虚析构函数支持RTTI:
struct ConstructType { virtual ~ConstructType() = default; // 必须加虚函数才能用dynamic_cast protected: ConstructType() {} }; // write方法修改为: void write(nlohmann::json& json) { if (auto* set_type = dynamic_cast<const SetConstructType*>(constructType)) { json_serialize(set_type, json); } else if (auto* append_type = dynamic_cast<const AppendConstructType*>(constructType)) { json_serialize(append_type, json); } }
这种方案有运行时类型检查开销,新增构造类型时需要同步修改分支逻辑。
关于SFINAE的疑问
你当前的设计不属于SFINAE的应用。SFINAE是Substitution Failure Is Not An Error的缩写,指的是模板实例化替换过程中如果出现类型不匹配的错误,编译器不会直接报错,而是会跳过这个重载继续匹配其他候选。你现在的写法还没有用到模板重载的替换逻辑,和SFINAE无关。
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

