лямбда-выражение для назначения указателя на функцию-член - PullRequest
0 голосов
/ 19 февраля 2019

Мне нужен синтаксис для лямбда-выражения, которое будет возвращать указатель на функцию-член.

Например, у меня есть класс A:

class A
{
int x;
void (A::*SomeFunction)();
}

Я хочу установить SomeFunction на лямбду.Я попытался сделать это так:

A a();
a.SomeFunction = [this](){ printf("Hello from lambada %d",this->x);};

Проблема в том, что:

[this](){ printf("Hello from lambda %d",this->x);};

не дает мне указатель на функцию-член класса A. он дает мне указатель нанормальная функция.Как мне объявить внутри лямбда-выражения, что это функция-член A.

Альтернативно, если такое невозможно в cpp.Как вы предлагаете, я получу доступ к переменной x класса A из функции, на которую указывает SomeFunction, без использования виртуальных функций (этот вид кода будет выполняться около 700 раз в секунду).

Редактировать:

Чтобы было ясно, я забочусь о производительности.но главная причина, почему я нуждаюсь в этом, - это конкретные проблемы дизайна, а не производительность.Я понимаю, что это, вероятно, невозможно сделать в cpp.Предложения обходных путей приветствуются.

Ответы [ 4 ]

0 голосов
/ 12 июня 2019

Что ж, следите за будущими людьми, вот приятный ответ.Мне потребовалось время, чтобы разработать его.Я не знаю, идеально ли это, но выглядит хорошо для меня;

Первое, что мы сделаем, это создадим структуру "MemberLambda", мы будем использовать функцию пакета параметров, которая идеально подходит для того, что нам нужно:

template <class Parent,class Return, class...Params>
struct MemberLambda
{
Parent* self; // pointer to self
void (*lambda)(Parent * self,Params...);//the lambda
MemberLambda() = default;//Constructor
MemberLambda(Parent* self, void(*lambda)(Parent* self,Params...)) : 
self(self),lambda(lambda) {};//Constructor

Return operator()(Params... p) const { return lambda(self,p...); };
void operator=(void (*lambda)(Parent* self, Params...)) {
    this->lambda = lambda;
    }
}; 

Теперь мы можем его использовать.

Использование в классе

Вот пример класса с именем A:

class A {
public:
int someMember; 
MemberLambda<A, void, int, int> func = 
MemberLambda<A, void, int, int>(this, nullptr);
};

* Обратите внимание, что в приведенном выше примере мы устанавливаем лямбду на значение nullptr, но вы можете установить лямбду на лямбда-выражение.

Я решил, что лямбда будет членом "A", возьмите два типа int и верните void.Измените его для своих нужд.

Использование пользователем

Для пользователя легко использовать, например:

A a;
a.someMember = 3;
a.func = [](A* self, int a, int b){ std::cout << self->someMember + a + b; };
a.func(5,5);

Будет выводить 13, которые3 + 5 + 5.

Работает хорошо.

0 голосов
/ 19 февраля 2019

Невозможно добавить дополнительные методы в класс после его определения.Следовательно, поскольку в вашем классе A нет методов, невозможно установить A::SomeFunction для указания на какой-либо нестатический метод A.В качестве обходного пути вы могли бы иметь

void (*SomeFunction)(A*);

и

A a {};  // note {} instead of ()
a.SomeFunction = [](A* a){ /* do something with a->x */ };
0 голосов
/ 19 февраля 2019

Из комментариев:

Это часть реализации ECS.и я просто не желаю создавать новый класс для системы etch, я хочу дать пользователю возможность объявить систему в конструкторе сцены или наследовать от системного класса.

Вы хотите другое поведениеиз того же класса без какой-либо косвенности?Вам придется отказаться от одного.

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

template<typename T>
struct A : private T {
    A(T function) noexcept : T{std::move(function)} {}

    void SomeFunction() {
        (*this)(this);
    }

    int x = 0;
};

Затем его можно использовать так:

auto lambda = [](auto a){ printf("Hello from lambda %d",a->x); };
auto my_a = A{lambda}; // Generate a new A type from lambda

my_a.SomeFunction(); // calls the lambda!
0 голосов
/ 19 февраля 2019

Это невозможно по нескольким причинам.

Во-первых, указатель на функцию-член отличается по типу от указателя на автономную функцию, а не захватывающие лямбда-выражения могут быть преобразованы только в указатели на автономные функции.functions.

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

Однако,Вы не должны слишком много думать об этом и просто хранить лямбду в std::function.Конечно, вы закончите с виртуальной диспетчеризацией и некоторым ухудшением производительности, связанным с этим, но 700 раз в секунду - это ничто, и вы никогда не обнаружите попадание из-за виртуальной диспетчеризации.

...