Контекст:
Встроенный c ++ без использования кучи.
Я хочу освоить свой код (включая его размер), поэтому я бы предпочел не использовать стандартныйlib, такой как std :: function.
1-й подход:
Давайте рассмотрим этот пример (который является упрощенной версией моего кода) с использованием модифицированной версии CRTP :
Примечание: метод моего обратного вызова может иметь 2 подписи: bool (ChildCrtp::*)(void);
и void (ChildCrtp::*)(int)
(одна для действия, одна для условия).
#include <iostream>
#include <stdint.h>
using namespace std;
void* operator new(size_t size)
{
cout << "ERROR HEAP USED" << endl;
}
template <typename FunctionType = void, typename... ArgumentType>
class GenericCallback
{
public:
virtual ~GenericCallback(){}
virtual FunctionType Execute(ArgumentType... arg) = 0; //!< execute callback
virtual bool IsValid() const = 0; //!< check if callback is valid
};
template <typename ObjectType, typename FunctionType = void, typename... ArgumentType>
class Callback : public GenericCallback<FunctionType, ArgumentType...>
{
public:
Callback() ://!< Default constructor
pObject_m(0),
pFunction_m(0)
{
}
Callback(ObjectType* pObject_m, FunctionType(ObjectType::*pFunction_m)(ArgumentType...))//!< Constructor
{
this->pObject_m = pObject_m;
this->pFunction_m = pFunction_m;
}
virtual FunctionType Execute(ArgumentType... arg)//!< execute callback implementation
{
return (pObject_m->*pFunction_m)(arg...);
}
virtual bool IsValid(void) const//!< callback validity check implementation
{
return (pObject_m != 0) && (pFunction_m != 0);
}
private:
ObjectType* pObject_m; //!< pointer to object where the callback is defined
FunctionType(ObjectType::* pFunction_m)(ArgumentType...); //!< pointer to the callback (function-member) of the object
};
template<typename ChildCrtp>
class Interface
{
public:
using FooSpecificCallback = Callback<ChildCrtp, bool>;
virtual int getValue(void) = 0;
bool IsPositive() { return (getValue() > 0); };
bool IsNegative(void) { return (getValue() < 0); };
bool IsEven(void) { return ((getValue() % 2) == 0); };
bool IsOdd(void) { return ((getValue() % 2) == 1); };
FooSpecificCallback isPositive_ = FooSpecificCallback(static_cast<ChildCrtp*>(this), &Interface::IsPositive);//line to be removed
FooSpecificCallback isNegative_ = FooSpecificCallback(static_cast<ChildCrtp*>(this), &Interface::IsNegative);//line to be removed
FooSpecificCallback isEven_ = FooSpecificCallback(static_cast<ChildCrtp*>(this), &Interface::IsEven);//line to be removed
FooSpecificCallback isOdd_ = FooSpecificCallback(static_cast<ChildCrtp*>(this), &Interface::IsOdd);//line to be removed
};
class Mother
{
public:
using FooGenericCallback = GenericCallback<bool>* ;
int getValue(){return x_;};
void storeCallback(FooGenericCallback pCallback){pCallback_ = pCallback;};
bool callCallback(){return (pCallback_->IsValid() == false)?:pCallback_->Execute();};
private:
int x_ = 3;
FooGenericCallback pCallback_;
};
class Child : public Mother, public Interface<Child>
{
public:
int getValue(){return Mother::getValue();}
void setup(void){storeCallback(&isPositive_);}
};
int main()
{
Child c;
c.setup();
cout << std::boolalpha << "Is " << c.getValue() << " positive? " << c.callCallback() << endl;
return 0;
}
В этом проекте есть несколько проблем:
- объекты обратного вызова сохраняются дважды
- интерфейс имеет атрибуты, не являющиеся членами-функциями: обратные вызовы.
- больно писать библиотеку, потому что вам нужно написать метод и обратный вызов, и вы должны определить его во всех классах, которые используют ваши обратные вызовы!
- возможно использование CRTP не подходит,Почему я использую CRTP?См. [Здесь]. ( Как определить шаблонный тип, который может быть унаследован? )
Решение?
Этодаже возможно?
Я на правильном пути?Если нет, то какой инструмент подходит?
Я гуглил и нашел несколько треков, но все еще не могу понять, как это сделать:
1) используя шаблонtypedef
Не понимаю, как
2) работает как аргумент шаблона
Я знаю, чтоПередача функции в качестве аргумента шаблона возможно / допустимо
Но моя попытка не удалась:
#include <iostream>
#include <stdint.h>
using namespace std;
void* operator new(size_t size)
{
cout << "ERROR HEAP USED" << endl;
}
template <typename FunctionType = void, typename... ArgumentType>
class GenericCallback
{
public:
virtual ~GenericCallback(){}
virtual FunctionType Execute(ArgumentType... arg) = 0; //!< execute callback
virtual bool IsValid() const = 0; //!< check if callback is valid
};
template <typename ObjectType, typename FunctionType = void, typename... ArgumentType>
class Callback : public GenericCallback<FunctionType, ArgumentType...>
{
public:
Callback() ://!< Default constructor
pObject_m(0),
pFunction_m(0)
{
}
Callback(ObjectType* pObject_m, FunctionType(ObjectType::*pFunction_m)(ArgumentType...))//!< Constructor
{
this->pObject_m = pObject_m;
this->pFunction_m = pFunction_m;
}
virtual FunctionType Execute(ArgumentType... arg)//!< execute callback implementation
{
return (pObject_m->*pFunction_m)(arg...);
}
virtual bool IsValid(void) const//!< callback validity check implementation
{
return (pObject_m != 0) && (pFunction_m != 0);
}
private:
ObjectType* pObject_m; //!< pointer to object where the callback is defined
FunctionType(ObjectType::* pFunction_m)(ArgumentType...); //!< pointer to the callback (function-member) of the object
};
template<typename ChildCrtp>
class Interface
{
public:
using FooSpecificCallback = Callback<ChildCrtp, bool>;
using FooPrototype = bool(Interface::*)();
template<FooPrototype op>
FooSpecificCallback* checkIf(void)
{
//I'm trying to take the address of this temporary object, which is not legal in C++.
return &FooSpecificCallback(static_cast<ChildCrtp*>(this), op);
}
virtual int getValue(void) = 0;
bool IsNegative() { return (getValue() < 0); };
};
class Mother
{
public:
using FooGenericCallback = GenericCallback<bool>*;
int getValue(){return x_;};
void storeCallback(FooGenericCallback pCallback){pCallback_ = pCallback;};
bool callCallback(){return (pCallback_->IsValid() == false)?:pCallback_->Execute();};
private:
int x_ = 3;
FooGenericCallback pCallback_;
};
class Child : public Mother, public Interface<Child>
{
public:
int getValue(){return Mother::getValue();}
void setup(void){storeCallback(checkIf<&Child::IsNegative>());}
};
int main()
{
Child c;
c.setup();
cout << std::boolalpha << "expectFalse: " << c.callCallback() << endl;
return 0;
}
Я получаю следующую ошибку
error: taking address of temporary [-fpermissive]
Поскольку невозможно получить адрес временного объекта, что недопустимо в C ++.
Проблема этого интерфейса обратного вызова заключается в том, что для хранения объекта "FooGenericCallback" требуется указатель, которыйне может быть "FooSpecificCallback", потому что тип объекта не известен в родительском классе.
3) другой способ реализовать обратный вызов в качестве интерфейса
как реализовать обратный вызов в качестве интерфейса
Но решение все еще используетобъект для хранения функций-членов в интерфейсе (или в дочерних элементах интерфейса).
4) Lambdas ...
Я знаючто лямбды упростили бы мою жизнь, на самом деле я сначала сделал это с лямбдами, а размер кода был удвоен с 60 кБ до 120 кБ (!) из-за способа хранения лямбд: в std :: function.Разве ответ не будет "лямбда":)