Как связать «это» с помощью шаблонов вместо макросов? - PullRequest
2 голосов
/ 16 октября 2019

Я пытаюсь заменить все макросы в моем коде шаблонами. У меня есть макрос, который связывает this в качестве первого аргумента функции, чтобы функцию-член можно было использовать в статическом контексте. Как я могу добиться этого с помощью шаблонов?

Я хотел бы эту функциональность:

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

Или с лямбдами:

#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();
}

Ответы [ 2 ]

5 голосов
/ 16 октября 2019

Я пытаюсь заменить все макросы в моем коде шаблонами.

Вы не можете. Несмотря на то, что шаблоны могут многое сделать, есть много вещей, которые могут обрабатываться только макросами.

Шаблоны - это шаблоны, которые генерируют типы, функции или переменные. Как таковые, они должны жить в рамках правил типов, функций или переменных C ++. Определение (не лямбда) функции не может попасть в область, в которой оно было объявлено, и просто вытащить вещи. Например, this. Область действия функции изолирована;он не может получить доступ к вещам вне своей области видимости (вне глобальных переменных и членов классов).

Следовательно, функция шаблона также не может этого делать. Двухфазный поиск позволяет каким-то образом влиять на шаблоны доступными именами в зависимости от того, где они создаются, но это крайне ограничено и в этом случае вам совсем не поможет.

Вы можете 't сделать экземпляр шаблона импортирующим this автоматически из того места, где был создан экземпляр шаблона. Вы можете передать this в качестве параметра функции, и он может использовать это значение в выражении связывания, но шаблон не может найти и найти this сам по себе.

2 голосов
/ 17 октября 2019

Может помочь шаблон класса «Любопытно повторяющийся шаблон» ( 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...