【问题标题】:How to bind 'this' using templates instead of macros?如何使用模板而不是宏来绑定“this”?
【发布时间】:2019-10-16 19:36:25
【问题描述】:

我正在尝试用模板替换我的代码中的所有宏。我有一个将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();
}

【问题讨论】:

  • 参数t在最后一个sn-p中应该是func
  • 您需要将 this 传递给 bind_event_fn 以便 lambda 可以捕获它。与宏不同,函数在自己的范围内运行。
  • @foreknownas_463035818 是的,已修复

标签: c++ lambda c++17 stdbind


【解决方案1】:

我正在尝试用模板替换我的代码中的所有宏。

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

模板是生成类型、函数或变量的模式。因此,它们必须符合 C++ 类型、函数或变量的规则。 (非 lambda)函数定义无法进入声明它的范围,只能将内容拉出。比如this。一个函数的作用域是孤立的;它不能访问其范围之外的东西(全局变量和类成员之外)。

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

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

【讨论】:

    【解决方案2】:

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

    你的代码已经到位:

    #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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-23
      • 2018-06-03
      • 2023-01-31
      • 2011-01-28
      相关资源
      最近更新 更多