1

有人可以给我这个问题的想法。我已经在互联网上搜索过这个,但无法获得我想要的太多信息。

说有课。

class Foo {
  explicit Foo() {}

  int getVar1();
  int getVar2();

  void setVar1(int v);
  void setVar2(int v);

  private:
  int var1, var2;
};

现在给出一个令牌列表 {"var1", "var2", ... "varN"},有什么方法可以在运行时创建函数名并调用 Foo 类型的某些对象的那些成员函数。喜欢例如

Foo obj;
string input = "Var1,Var2,Var3,...VarN";
vector<string> tokens = splitString(input);
for (vector<string>::const_iterator it = tokens.begin(); it != tokens.end(); ++it) {
  string funName = "get" + *it;
  // somehow call obj.getVar1()....obj.getVarN()
}

使用 if else 适用于少量变量,但不适用于大量变量。使用 bind 和 functors 也不能解决这个问题。一个网页建议在运行时使内存可执行,然后使用 reinterpret_cast,我不知道这是否可行。

更新

好的,从互联网上的答案和其他搜索中,我看到在 C++ 中没有优雅的方式来做到这一点。到目前为止,C++ 中还没有反射。所有 hack 都需要成员函数指针的编译时解析。当你有很多变量和 setter 和 getter 函数时,有人可以给我关于替代类设计的想法......或者 getter 和 setter 在 c++ 中是否是好的实践?

4

5 回答 5

4

作为一个想法,请考虑以下代码

struct A
{
    void f1() { std::cout << "A::f1()\n"; }
    void f2() { std::cout << "A::f2()\n"; }
    void f3() { std::cout << "A::f3()\n"; }
    void f4() { std::cout << "A::f4()\n"; }
};

std::map<std::string, void( A::* )()> m = { { "f1", &A::f1 }, { "f2", &A::f2 }, { "f3", &A::f3 }, { "f4", &A::f4 } };

A a;

for ( auto p : m ) ( a.*p.second )();

您可以将地图作为类的数据成员。

于 2013-12-04T20:47:48.813 回答
2

您不能在运行时“添加”成员。C++ 在编译时是强类型的。

您可以通过拥有 amap<string, func_type>并使用它将字符串解析为实际函数来获得所需的行为。您可以使用宏创建它以确保字符串名称与函数名称匹配。

#DEFINE ADD_METHOD(map_var, func) map_var["func"] = &func
于 2013-12-04T20:32:42.150 回答
0

为什么不以参照的方式看待它:为每个变量分配一个索引号,从 0、1、2.... 这些变量的所有值都保存在一个数组中,以便第一个变量的值在单元格 0 中,下一个变量在单元格 1 中,依此类推。

因此,当您想要获取/设置值时,您需要做的就是在地图中找到它的索引,然后访问向量中的相关单元格。

于 2013-12-04T21:15:06.137 回答
0

一个简单/不完美的解决方案可能是使用中间方法检查参数并相应地调用 getVar* 方法。

像这样的一个例子可能是:

class Foo 
{
public:
    explicit Foo() {}

    int getVar1() { return 1; }
    int getVar2() { return 2; }

    void setVar1(int v) { var1 = v; }
    void setVar2(int v) { var2 = v; }

    int callGetVar(const std::string &var)
    {
        if (var == "Var1") return getVar1();
        if (var == "Var2") return getVar2();
        else { return -1; }
    }

private:
    int var1, var2;
};

int main()
{
    Foo obj;
    std::string input = "Var1,Var2,Var3,...VarN";
    std::vector<std::string> tokens = { "Var1", "Var2", "Var2", "Var1", "Var1", "Var2", "Var2", "Var1"};
    auto tokensIT = tokens.begin();
    for (; tokensIT != tokens.end(); ++tokensIT) 
    {
        // somehow call obj.getVar1()....obj.getVarN()
        std::cout << obj.callGetVar(*tokensIT);
    }

    return 0;
}
于 2013-12-04T20:42:42.813 回答
0

你可以试试这个

一个例子:

template<class C1, class C2, class R, class... A, std::size_t... I>
boost::json::value
call_impl_(C1& c1, R(C2::* pmf)(A...), boost::json::array const& args,
    std::index_sequence<I...>)
{
    return boost::json::value_from(
        (c1.*pmf)(boost::json::value_to< boost::remove_cv_ref_t<A> >(args[I])...));
}

template<class C1, class C2, class R, class... A>
boost::json::value
call_impl(C1& c1, R(C2::* pmf)(A...), boost::json::array const& args)
{
    if (args.size() != sizeof...(A))
    {
        throw std::invalid_argument("Invalid number of arguments");
    }
    return call_impl_(c1, pmf, args, std::index_sequence_for<A...>());
}

template<class C>
boost::json::value
call(C& c, boost::string_view method, boost::json::value const& args)
{
    using Fd = boost::describe::describe_members<C,
        boost::describe::mod_public | boost::describe::mod_function>;
    bool found = false;
    boost::json::value result;
    boost::mp11::mp_for_each<Fd>([&](auto D) {
        if (!found && method == D.name)
        {
            result = call_impl(c, D.pointer, args.as_array());
            found = true;
        }
        });
    if (!found)
    {
        throw std::invalid_argument("Invalid method name");
    }
    return result;
}

//test1 from https://github.com/bytemaster/boost_reflect 
struct calculator {     //need Generic maybe..
    int add(int v, int u) { return u + v; }
    int sub(int v) { return result_ -= v; }
    int result() { return result_; }
private:
    int result_ = 0.0;
};

BOOST_DESCRIBE_STRUCT(calculator, (), (add, sub), (result));

int main(int argc, char** argv) {
    calculator cal;
    std::string line;
    std::string cmd;
    std::string args;

    while (true) {
        std::cerr << "Enter Method: ";
        std::getline(std::cin, line);
        int pos = line.find('(');
        cmd = line.substr(0, pos);
        args = line.substr(pos + 1, line.size() - pos - 2);
        std::cout << "args: " << args << std::endl;
        std::vector<std::string> num_str;
        boost::split(num_str, args, boost::is_any_of(","));
        std::vector<int> nums;
        std::for_each(num_str.begin(), num_str.end(), [&](std::string str) {nums.push_back(std::stoi(str)); });
        // Convert the vector to a JSON array
        const boost::json::value jv = boost::json::value_from(nums);
        std::cout << call(cal, cmd, jv) << std::endl;
    }
    return 0;
}

可以在visual studio 2022 c++17下通过。用cpp20会报错,不知道为什么

于 2021-11-27T17:51:32.603 回答