Использование std :: function в списке инициализации члена

У меня есть typedef:

typedef S32(iMyDataClass1::*getDataFunction_t)(void);

и тип:

struct functionMap_t {
std::vector<getDataFunction_t> pDataFunctionTable;
struct dataRequestor_t dataRequestor;
};

У меня тогда есть переменная-член:

functionMap_t FnMap1;

Который я тогда настроил в списке инициализатора участника:

myClass::myClass() : FnMap1({
{
&iMyDataClass1::getData1,
&iMyDataClass1::getData2,
&iMyDataClass1::getData3
},
dataRequestor1
})

Который я затем использую в конструкторе:

addNewFnMap(FnMap1);

Это все отлично работает. К сожалению, он не распространяется на указатели функций на разные классы, так как getDataFunction_t связан с указателями в iMyDataClass1

Я пытался использовать шаблоны, но столкнулся с проблемами, которые я не мог обойти. Сейчас я пытаюсь использовать std::function, что означает, что я изменяю оригинальный typedef на (я думаю):

typedef std::function<S32(void)> getDataFunction_t;

Как правильно настроить список инициализаторов в этой ситуации? Я использую std::bind Вот?

Обновить:
Вот моя попытка нового списка инициализатора. Я понятия не имею, если это правильно, но это то, что я имел право до публикации этого вопроса:

{
{
(std::bind(&iMyDataClass1::getData1, functionToFetchCorrectObject())),
(std::bind(&iMyDataClass1::getData2, functionToFetchCorrectObject())),
(std::bind(&iMyDataClass1::getData3, functionToFetchCorrectObject()))
},
PGN65370
}

4

Решение

Вы можете использовать лямбда-выражения. Однако, если вы хотите сохранить подпись как std::function<S32(void)>вам нужно будет захватить ваш объект.

myClass::myClass() : FnMap1({
{
[this](){ return getData1(); },
[this](){ return getData2(); },
[this](){ return getData3(); },
},
dataRequestor1
})

Если вы не хотите этого делать, вы можете изменить подпись, чтобы передать this указатель в качестве параметра для ваших обратных вызовов. Но, как отмечает Барри в комментариях, это не позволит вам помещать обратные вызовы для разных классов в один и тот же vector, Вы могли бы reinterpret_cast указатель внутри лямбды, но помимо того, что он уродлив и опасен, как вызывающий может узнать, какой указатель передать?

3

Другие решения

Если вы хотите, чтобы он работал с разными классами, вы можете просто хранить вызываемые элементы с любой сигнатурой:

struct functionMap_t {
std::vector<std::function<S32(void)>> pDataFunctionTable;
struct dataRequestor_t dataRequestor;
};

Далее, что я, вероятно, сделаю, это предоставлю вашему классу функции более высокого порядка, которые возвращают std :: functions с правильной сигнатурой.

std::function<S32(void)> iMyDataClass1::getData1Getter() {
auto f = [this] () {return this->getData1()};
return f;
}

Теперь вы можете инициализировать довольно просто:

iMyDataClass1 o;
...

FnMap1({o.getData1Getter(), ..., dataRequestor1});

Этот код не был тщательно проверен, и я уверен, что он содержит синтаксические ошибки. Но это должно дать вам суть этого. Основная идея такова: если вы хотите работать с функциями, которые могут или не могут быть прикреплены к определенным объектам, то вам нужно работать с функциями (на самом деле, самими замыканиями). Работа с функциями такого рода мотивирует дизайн, который использует функции более высокого порядка, чтобы возвращать функции из одного контекста и передавать их в другой.

РЕДАКТИРОВАТЬ: Недавно я имел несколько дизайнерских бесед с кем-то о шаблоне Observer в C ++ 11. Я рекомендовал сделать что-то очень похожее на это, это может быть очень хорошо, избегая использования полиморфизма, чтобы сделать вещи общими и отделенными, и избежать загрязнения иерархии наследования.

2

По вопросам рекламы [email protected]