【问题标题】:About std::function usage and if-else problem关于 std::function 使用和 if-else 问题
【发布时间】:2021-12-24 15:45:20
【问题描述】:

正如下面的代码,我不想要这么多“if else”

class A
{
public:
    void f0()
    {
        cout << "f0" << endl;
    }
    void f1()
    {
        cout << "f1" << endl;
    }
    void f2()
    {   
        cout << "f2" << endl;
    }
    //..... more functions fn()...
};


class B
{
public:
    void f(int n)
    {
        //vector< function<void()> > f_v {obj_a.f0, obj_a.f1, obj_a.f2}; //this usage is not correct
        if (n == 0)
            obj_a.f0();
        else if (n == 1)
            obj_a.f1();
        else if (n == 2)
            obj_a.f2();
        //.....more else if here
    }
private:
    A obj_a;
};

我想创建一个vector并使用std::function来避免使用这么多if-else,比如vector&lt; function&lt;void()&gt; &gt; f_v {obj_a.f0, obj_a.f1, obj_a.f2};但是不行,可能std::function的用法不是很正确。我应该怎么做? 或者有什么其他好的方法可以解决if else的问题,我觉得用这么多switch-case也不是很优雅:)

更新: 一些答案已经解决了我之前代码中std::function的使用问题;

更一般地,考虑下面的代码,如果成员函数 A::f1(), A::f2().... 有不同的返回类型,但仍然有一些联系,它们派生自同一个基类,在B::f()中实现if else的逻辑有什么好办法?

class Base 
{
public:
    virtual ~Base()=default;

};

class D1 : public Base
{
public:

};

class D2 : public Base
{
public:

};

class D3 : public Base
{
public:

};
// ....maybe more class derived form Base
class A
{
public:
    D1* f0()
    {
        cout << "f0" << endl;
        return &d1;
    }
    D2* f1()
    {
        cout << "f1" << endl;
        return &d2;
    }
    D3* f2()
    {   
        cout << "f2" << endl;
        return &d3;

    }
    //more fn()....

private:
    D1 d1;
    D2 d2;
    D3 d3;
    //.....
};

class B
{
public:
    void f(int n)
    {
        if (n == 0)
            obj_a.f0();
        else if (n == 1)
            obj_a.f1();
        else if (n == 2)
            obj_a.f2();
        //.....more else if here
    }
private:
    A obj_a;
};

【问题讨论】:

  • 这听起来完全正确。您能告诉我们您尝试使用std::function 做什么,我们可以从那里指导您吗?
  • 你也可以在这里使用switch-case
  • 我真的觉得你应该稍微扩展一下你想要达到的目标,因为有很多方法可以解决它。如果您一心想要使用std::function,那么您已经有了答案,但是如果您尝试使用std::function,因为您认为这是唯一的解决方案,那么如果我们知道,实际上可能会有更好的解决方案确切的问题。
  • 我已经重新编辑了我的描述,感谢您的建议

标签: c++ if-statement std-function


【解决方案1】:

您可以将std::function 与 lambda 包装器一起使用,

vector<function<void()>> f_v {[this]() { obj_a.f0(); }, 
                              [this]() { obj_a.f1(); }, 
                              [this]() { obj_a.f2(); }};
f_v[n]();

或者直接使用指向成员的指针,

vector<void (A::*)()> f_v { &A::f0, &A::f1, &A::f2 };
(obj_a.*f_v[n])();

【讨论】:

  • 谢谢,您的回答可以很好。但是如果函数的返回类型不同,如何让它工作呢?或者如果我必须尝试其他方法来实现?
  • std::function 方法适用于不同的返回类型;处理 lambda 中的返回值。
【解决方案2】:

如果您的目标是速度并且您知道方法的数量,请避免使用 std::vector 进行额外的间接操作。使用 std::array 因为它将与当前对象一起命中缓存。

对于这种简单的情况,您不一定需要使用 std::function,这是一个非常繁重的调用对象。您可以像这样使用指向成员的指针:

#include <iostream>
#include <array>

using namespace std;

class A
{
public:
    void f0()
    {
        cout << "f0" << endl;
    }
    void f1()
    {
        cout << "f1" << endl;
    }
    void f2()
    {   
        cout << "f2" << endl;
    }
    //..... 
};


class B
{
public:
    B() {
        fn[0] = &A::f0;
        fn[1] = &A::f1;
        fn[2] = &A::f2;
    }
    void f(int n)
    {
        ((obj_a).*(fn[n]))();
    }
private:
    using Fn = void (A::*)();
    std::array<Fn,3> fn;
    A obj_a;
};

代码:https://godbolt.org/z/z4KqKvn99

【讨论】:

  • 这是正确的答案。不需要std::functionstd::vector 的开销。
  • 只有一件事:括号太多! (obj_a.*fn[n])() 就足够了。
【解决方案3】:

您的方法似乎是正确的。你只需要 std::bind 像

这样的成员函数
class B{
std::vector <std::function <void()>> m_vec_functs; 
...
B(const A& a)
{
 m_vec_functs.push_back(std::bind(&A::f0, a));
 m_vec_functs.push_back(std::bind(&A::f1, a));
}

void f(unsigned int n)
{
 m_vec_functs[n];
}
...
};

然后您可以通过索引访问每个单独的函数,知道它们的顺序。

【讨论】:

  • 请不要使用绑定,除非限制在 03 或更早。
  • 我会读一点并了解原因。谢谢@Taekahn
猜你喜欢
  • 2022-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-04
  • 1970-01-01
  • 2023-03-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多