如何使用模板而不是宏来绑定 'this'?

How to bind 'this' using templates instead of macros?

我正在尝试用模板替换代码中的所有宏。我有一个宏将 this 绑定为函数的第一个参数,以便可以在静态上下文中使用成员函数。我如何使用模板实现这一点?

我想要这个功能:

#define BIND_EVENT_FN(func) std::bind(&func, this, std::placeholders::_1)

或使用 lambda:

#define BIND_EVENT_FN(func) [this](Event& e){ return func(e); }

与此类似,但显然不太像这样,因为它无法编译:

template<class T>
auto bind_event_fn(T& func)
{
    return [this](Event&& e){ return func(e); };
}

下面的最小工作示例,是否可以替换宏?

#include <functional>
#include <iostream>

#define LAMBDA_BIND_FN(fn) [this](const int& event) { return fn(event); }
#define BASIC_BIND_FN(func) std::bind(&func, this, std::placeholders::_1)

void run_in_static_context(std::function<void(const int&)> fn)
{
    fn(42);
}

class A {
  public:
    A()
    {
        run_in_static_context(LAMBDA_BIND_FN(A::member_fn));
    }
  private:
    void member_fn(const int& event)
    { 
        std::cout << "Event: " << event << std::endl;
    }
};

int main()
{
    A();
}

I am trying to replace all macros in my code with templates.

你不能。虽然模板可以做很多事情,但有很多事情只能由宏来处理。

模板是生成类型、函数或变量的模式。因此,它们必须遵守 C++ 类型、函数或变量的规则。一个(非 lambda)函数定义不能进入它被声明的范围,只能把东西拉出来。例如 this。函数的范围是隔离的;它不能访问其范围之外的东西(在全局变量和 类 的成员之外)。

因此,模板函数也不能做到这一点。两阶段查找确实允许模板在某种程度上受到基于实例化位置的可访问名称的影响,但这是非常有限的,在这种情况下对您根本没有帮助。

您不能从模板实例化的地方自动导入模板实例化 this。您可以将 this 作为参数传递给函数,它可以在绑定表达式中使用该值,但模板无法自行找到 this

一个奇怪的重复模板模式 (CRTP) class 模板可以提供帮助。创建一个 class 模板,将应与 this 一起使用的宏转换为成员函数。然后,您必须在应该有权访问任何功能的 classes 中继承它。

您的代码:

#include <functional>
#include <iostream>

template<typename T>  // T = the child class
struct bind_helper {
    // put "class macros" in here, translated into functions

    template<class F>
    inline auto lambda_bind_fn(F func) {
        return // a lambda that will cast "this" to a "T*" (the class that inherited
               // bind_helper) then dereference "func" and call it
            [this, func](const int& e) { return (static_cast<T*>(this)->*func)(e); };
    }
};

void run_in_static_context(std::function<void(const int&)> fn) {
    fn(42);
}

class A : public bind_helper<A> { // inherit with the class itself as template parameter
public:
    A() { 
        run_in_static_context(lambda_bind_fn(&A::member_fn)); 
    }

private:
    void member_fn(const int& event) {
        std::cout << "Event: " << event << std::endl;
    }
};

int main() {
    A x;
}

输出:

Event: 42