C++:无结构体实例时关联键值与非静态成员的实现方案
如何在无struct实例时关联文件键与成员?
你想要在未创建struct实例的前提下,定义文件键与struct成员的关联关系,后续用该关联填充实例。直接使用Foo::bar的方式确实会报错,因为非静态成员不能脱离实例直接引用,但可以通过成员指针这一元编程相关技术实现需求,同时也可以用你提到的回调方案增强灵活性。
成员指针实现方案
成员指针本质是一种指向类/struct成员的指针,无需实例即可传递“访问该成员”的信息。我们可以用它来建立键与成员的映射,后续有实例时再完成赋值:
#include <string> #include <unordered_map> #include <functional> struct Foo { int bar; int baz; }; // 存储类型T的键-成员操作映射 template<typename T> std::unordered_map<std::string, std::function<void(T&, int)>> s_member_ops; // 关联文件键与struct成员 template<typename T, typename MemType> void map2member(const std::string& memberKey, MemType T::*memberPtr) { s_member_ops<T>[memberKey] = [memberPtr](T& instance, int value) { instance.*memberPtr = value; }; } // 填充实例的工具函数 void populateFoo(Foo& instance, const std::string& key, int value) { auto iter = s_member_ops<Foo>.find(key); if (iter != s_member_ops<Foo>.end()) { iter->second(instance, value); } } int main() { // 提前建立关联,无需Foo实例 map2member<Foo>("bar", &Foo::bar); map2member<Foo>("baz", &Foo::baz); // 后续创建实例并填充 Foo myFoo; populateFoo(myFoo, "bar", 123); populateFoo(myFoo, "baz", 456); // myFoo.bar = 123,myFoo.baz = 456 return 0; }
这里MemType T::*memberPtr是指向T类型中MemType成员的指针,通过lambda将其包装成可执行的赋值操作,存入映射表。当有实例时,通过instance.*memberPtr即可访问并修改对应成员。
回调函数方案
如果你需要处理更复杂的逻辑(比如字符串转不同类型、校验值等),回调方案会更灵活:
#include <string> #include <unordered_map> #include <functional> #include <stdexcept> struct Foo { int bar; int baz; }; template<typename T> std::unordered_map<std::string, std::function<void(T&, const std::string&)>> s_member_callbacks; template<typename T> void map2member(const std::string& memberKey, std::function<void(T&, const std::string&)> callback) { s_member_callbacks<T>[memberKey] = callback; } void populateFoo(Foo& instance, const std::string& key, const std::string& rawValue) { auto iter = s_member_callbacks<Foo>.find(key); if (iter != s_member_callbacks<Foo>.end()) { iter->second(instance, rawValue); } } int main() { map2member<Foo>("bar", [](Foo& f, const std::string& val) { try { f.bar = std::stoi(val); } catch (const std::invalid_argument&) { // 处理非法值逻辑 f.bar = 0; } }); map2member<Foo>("baz", [](Foo& f, const std::string& val) { f.baz = std::stoi(val); }); Foo myFoo; populateFoo(myFoo, "bar", "123"); populateFoo(myFoo, "baz", "456"); return 0; }
总结
你最初直接引用Foo::bar的写法无法实现,但通过成员指针可以达到“提前关联键与成员访问方式”的核心需求;回调方案则在灵活性上更胜一筹,适合处理复杂的解析逻辑。
内容的提问来源于stack exchange,提问作者user2169513
相关产品推荐
相关产品推荐

