提供一个指向目标类要调用的成员函数的指针,而不是函数

问题描述

我正在阅读很多关于函数指针、函子和回调的问题(和答案),但我仍然不清楚哪种工具适合我。

其中一些不适用于我的场景,因为我的编译器 avr-gcc v5.4.0 似乎没有 C++ 标准库(即 std::function 不可用)。

这是我的基类:

class Debouncer
{
public:
    typedef uint8_t (Debouncer::*debouncer_raw_t) (void);

    Debouncer() {}
    void setRawFunction(Debouncer::debouncer_raw_t callback) { _raw = callback; }

private:
    debouncer_raw_t _raw;
    void anotherFunction()
    {
        uint8_t value = _raw();
        // do something
    }
}

在我的其他课程中:

class Inputs
{
public:
    Inputs()
    {
        _deb.setRawFunction(myRaw);
    }

private:
    Debouncer _deb;
    uint8_t myRaw()
    {
        return something;
    }
}

当然这不会编译,因为 myRaw 不是静态的。 无论如何,我将尽量避免这种情况,因为它会破坏现有代码。

如果我没记错的话,很多问题似乎都是反过来问的。 相反,我只想将我的成员函数的指针传递给我的 Debouncer 类,以便它可以在需要时调用 _raw()

Here 我发现这个建议可以避免使用 std:: 库:

#define CALL_MEMBER_FN(object,ptrToMember)  ((object).*(ptrToMember))

void userCode(Fred& fred,FredMemFn p)  // Use a typedef for pointer-to-member types
{
  int ans = CALL_MEMBER_FN(fred,p)('x',3.14);
  // Would normally be: int ans = (fred.*p)('x',3.14);
  // ...
}

但似乎相反。这里的 Fred 类是我的 Debouncer。 我不想调用 Debouncer 成员,而是调用 caller 类的成员(即 Input::myRaw())。

能否请您帮我了解一下哪种工具适合完成如此简单的任务?

解决方法

如果您知道(或要求)每个使用 Debouncer 的类都有一个公共 myRaw() 函数(或者更好的 operator(),或者实际上是其他任何函数),那么问题就简单了:

template <typename T>
class Debouncer
{
public:
    Debouncer (T* t): _t(t) {}
    void anotherFunction()
    {
        uint8_t value = _t->myRaw();
        std::cout << static_cast<int>(value);
    }
    
private:
    T* _t;
};

class Inputs
{
public:
    Inputs() : _deb(this)
    {
        // beware,if Debouncer uses its parameter in constructor (like call a method),// you cannot use initializer list
    }
    
    uint8_t myRaw()
    {
        return 13;
    }
    
    void foo()
    {
        _deb.anotherFunction();
    }

private:
    Debouncer<Inputs> _deb;
};

int main()
{
    Inputs i;
    i.foo();
}

这将是 C++ 中的首选解决方案。例如,参见标准库 <algorithm> - 任何采用谓词或其他可调用的函数都希望使用 operator() 调用它,而不必处理指向成员函数的指针。

如果你不知道应该调用什么函数并且你真的不能对类强加任何要求,你需要存储一个指向类的指针(或引用)和一个指向成员函数的指针。注意不能连接指向不同类成员函数的指针,所以我们再次需要模板:


template <typename T,typename Func>
class Debouncer
{
public:
    Debouncer (T* t,Func f): _t(t),_f(f) {}
    void anotherFunction()
    {
        uint8_t value = (_t->*_f)(); //I get it now why isocpp asks to use macro here,the syntax is horrible
        std::cout << static_cast<int>(value);
    }
    
private:
    T* _t;
    Func _f;
};

class Inputs
{
public:
    Inputs() : _deb(this,&Inputs::myRaw)
    {
        // beware,// you cannot use initializer list
    }
    
    uint8_t myRaw()
    {
        return 13;
    }
    
    void foo()
    {
        _deb.anotherFunction();
    }

private:
    Debouncer<Inputs,decltype(&Inputs::myRaw)> _deb; //decltype is C++11,you could also declare type like you did in your question

};

int main()
{
    Inputs i;
    i.foo();
}
,

创建成员函数 virtual 是一种开销相对较低的方法,可以让单个指针(指向对象)同时指向对象的数据和正确的成员函数。

class InputsBase
{
    // All classes that implement myRaw() should inherit from this class
public:
    virtual uint8_t myRaw() = 0;
};

class Inputs : public InputsBase
{
public:
    Inputs()
    {
        _deb.setRawFunction(this);
    }

private:
    Debouncer _deb;
    virtual uint8_t myRaw()
    {
        return something;
    }
}

然后你的 Debouncer 可以简单地存储一个指向相关对象的指针。

class Debouncer
{
public:
    typedef InputsBase* debouncer_raw_t;

    Debouncer() {}
    void setRawFunction(debouncer_raw_t callback) { _raw = callback; }

private:
    debouncer_raw_t _raw;
    void anotherFunction()
    {
        uint8_t value = _raw->myRaw();
        // do something
    }
}

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...