提供一个指向成员函数的指针,由目标 class 调用而没有函数

Provide a pointer to member function to be invoked by the target class without functional

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

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

这是我的基地class:

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
    }
}

在我的其他 classes 中,我有:

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

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

当然这不会编译,因为 myRaw 不是静态的。 不管怎样,我会尽量避免这种情况,因为它会破坏现有代码。

如果我没记错的话,很多问题似乎都是反过来问的。 相反,我只想将我的成员函数的指针传递给我的 Debouncer class,以便它可以在需要时调用 _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);
  // ...
}

但似乎恰恰相反。这里的 class Fred 是我的 Debouncer。 我不想呼叫 Debouncer 成员,而是 caller class 的成员(即 Input::myRaw())。

能否请您帮助我了解实现如此简单任务的正确工具?

如果您知道(或要求)每个使用 Debouncer 的 class 都有一个 public 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() 来调用它,而不是必须处理指向成员函数的指针。

如果你不知道应该调用什么函数并且你真的不能对 class 施加任何要求,你需要存储指向 class 的指针(或引用)和指向成员函数的指针。请注意,您不能将指针连接到不同 class 的成员函数,因此我们再次需要模板:


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, 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, 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
    }
}