У меня есть 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
}
Вы можете использовать лямбда-выражения. Однако, если вы хотите сохранить подпись как std::function<S32(void)>
вам нужно будет захватить ваш объект.
myClass::myClass() : FnMap1({
{
[this](){ return getData1(); },
[this](){ return getData2(); },
[this](){ return getData3(); },
},
dataRequestor1
})
Если вы не хотите этого делать, вы можете изменить подпись, чтобы передать this
указатель в качестве параметра для ваших обратных вызовов. Но, как отмечает Барри в комментариях, это не позволит вам помещать обратные вызовы для разных классов в один и тот же vector
, Вы могли бы reinterpret_cast
указатель внутри лямбды, но помимо того, что он уродлив и опасен, как вызывающий может узнать, какой указатель передать?
Если вы хотите, чтобы он работал с разными классами, вы можете просто хранить вызываемые элементы с любой сигнатурой:
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. Я рекомендовал сделать что-то очень похожее на это, это может быть очень хорошо, избегая использования полиморфизма, чтобы сделать вещи общими и отделенными, и избежать загрязнения иерархии наследования.