gpt4 book ai didi

c++ - 关于摆脱样板代码的想法

转载 作者:行者123 更新时间:2023-11-30 02:15:03 25 4
gpt4 key购买 nike

我的问题非常具体。我有以下要求,出于多种原因,我需要从父类设置存在于子类中的成员变量。我的计划是在构造时将以字符串为参数的setter方法(存在于子类中)的函数指针传递给父类。父类定义了一个公共(public)方法,该方法以成员名称和值字符串为参数,并调用具有值字符串的成员的函数指针。父类可以存在于 dll 或 lib 中,并且无法访问任何转换或工厂方法,因此必须在子类中定义 setter 方法。

由于父类可以作为其他类的基类,我写了一些如下所示的宏:

#define DEFINE_VAL(Type, memberName) \
private: \
Type memberName; \
void set##memberName(std::string const& val) { \
memberName = convert_to_val(val); /* this will be a call to factory which converts string to value type*/\
/* or call to local implementation for conversion*/
}; \

#define INIT_VAL(memberName) \
{ memberName, \
[&](std::string const& val) { set##memberName(val); }}

父子类如下:

// parent.h probably in dll
class parent
{
public:
parent(std::map<std::string, std::function<void(std::string const&)>>& m)
: m(m)
{ }
...
private:
std::map<std::string, std::function<void(std::string const&)>> m;
};

// child.h
class child : public parent
{
public:
child() : parent({ INIT_VAL(iVal), ... })
{ }
private:
DEFINE_VAL(int, iVal);
...
};

子类可以定义很多变量,首先使用 DEFINE_VAL 宏,然后使用 INIT_VAL 宏传递每个变量的 setter 方法有点烦人。这可以在一个宏中完成吗(可能在 DEFINE_VAL 中)?或者关于自动注册成员名称和函数指针到父类的任何想法?

我也很感激任何关于完成我的要求的替代想法。

最佳答案

I need to set member variables that exist in child class from parent class, for several reasons. My plan is to pass a function pointer of the setter method (which exist in child class), that takes string as argument, to the parent class at construction.

当父类构造函数被调用时,派生类及其成员还没有被初始化,并且迂腐地说,它们还不存在。因此,不可能从其基类构造函数设置派生类成员。


一种解决方案是使用虚函数按名称设置成员。

在当前的 C++ 中没有内置反射,要将名称与数据成员相关联并生成成员访问器,最佳实践仍然是使用宏。为此目的最好的宏之一是 BOOST_HANA_DEFINE_STRUCT .

boost::lexical_cast<T>可用于从 std::string 转换到任何 T .

具有深度和多重继承支持的工作示例:

#include <boost/hana/define_struct.hpp>
#include <boost/hana/accessors.hpp>
#include <boost/hana/for_each.hpp>
#include <boost/hana/concat.hpp>
#include <boost/hana/length.hpp>

#include <boost/lexical_cast.hpp>

#include <unordered_map>
#include <functional>
#include <iostream>

namespace hana = boost::hana;

struct MemberSetter {
// Using void* to reduce the number of template instantiations.
using SetterFn = std::function<void(void*, std::string const&)>;
using Setters = std::unordered_map<std::string, SetterFn>;

Setters setters_;

template<class Derived, class Accessors>
MemberSetter(Derived* that, Accessors& accessors) {
hana::for_each(accessors, [this](auto const& pair) {
auto setter = [accessor = hana::second(pair)](void* vthat, std::string const& value) {
auto* that = static_cast<Derived*>(vthat);
auto& member = accessor(*that);
member = boost::lexical_cast<std::remove_reference_t<decltype(member)>>(value);
};
auto name = hana::first(pair);
setters_.emplace(std::string(hana::to<char const*>(name), hana::length(name)), std::move(setter));
});
}

bool findAndSetMember(void* that, std::string const& name, std::string const& value) const {
auto setter = setters_.find(name);
if(setter != setters_.end()) {
(setter->second)(that, value);
return true;
}
return false;
}
};

struct A {
virtual ~A() = default;
virtual bool setMember(std::string const& name, std::string const& value) = 0;
};

struct B : A {
BOOST_HANA_DEFINE_STRUCT(B,
(int, a),
(double, b)
);

bool setMember(std::string const& name, std::string const& value) override {
constexpr auto accessors = hana::accessors<B>();
static MemberSetter const setter(this, accessors);
return setter.findAndSetMember(this, name, value);
}
};

struct C : B {
BOOST_HANA_DEFINE_STRUCT(C,
(std::string, c)
);

bool setMember(std::string const& name, std::string const& value) override {
constexpr auto accessors = hana::concat(hana::accessors<B>(), hana::accessors<C>()); // Join with members of the base class.
static MemberSetter const setter(this, accessors);
return setter.findAndSetMember(this, name, value);
}
};

int main() {
C c;
c.setMember("a", "1");
c.setMember("b", "2.3");
c.setMember("c", "hello");
std::cout << c.a << ' ' << c.b << ' ' << c.c << '\n';
}

输出:

1 2.3 hello

关于c++ - 关于摆脱样板代码的想法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56732377/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com