上下文:
不使用堆的嵌入式c ++。
我想掌握我的代码(包括其大小),所以我不想使用标准的库,例如std :: function。
第一种方法:
让我们以修改后的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;
}
此设计有几个问题:
解决方案?
那有可能吗?
我走对了吗?如果没有,什么是正确的工具?
我已经在Google周围搜索并找到了几条曲目,但仍然不知道该怎么做:
1)使用模板typedef
不知道如何
2)用作模板参数
我知道将函数作为模板参数传递是possible/valid
但是我的尝试没有成功:
#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)另一种将回调实现为接口的方法
how to implement callback as an interface
但是该解决方案仍然使用对象将函数成员存储在接口(或接口的子级)中。
4)Lambdas ...
我知道lambda会简化我的生活,的确,我首先使用lambda做到了这一点,并且由于lambda的存储方式(在std :: function中),代码大小从60kB翻了一倍,达到了120kB(!)。答案不应该是“ lambda”:)
答案 0 :(得分:1)
我可能已经过分简化了您的需求,但是出了什么问题:
template<typename Base>
class Interface : public Base
{
public:
static bool IsNegative(Base* userData)
{
auto that = static_cast<Base*>(userData);
return that->getValue() < 0;
}
};
class Mother
{
public:
using Callback = bool (*) (Mother*);
int getValue() { return x_; }
void storeCallback(Callback pCallback) { pCallback_ = pCallback; }
bool callCallback() {return pCallback_ ? (*pCallback_)(this) : throw 42;}
private:
int x_ = 3;
Callback pCallback_;
};
class Child : public Interface<Mother>
{
public:
void setup(){ storeCallback(&Interface::IsNegative); }
};
int main()
{
Child c;
c.setup();
std::cout << std::boolalpha << "expectFalse: " << c.callCallback() << std::endl;
}
答案 1 :(得分:0)
我仍然不确定我是否正确理解你的意图。但是下面的代码编译没有错误,尽管我没有进一步测试它:
template<typename ChildCrtp>
class MotherInterface
{
protected:
//Callback types
using SomethingBooleanCallback = bool (ChildCrtp::*)();
protected:
//Helper methods
bool AlwaysTrue(void) { return true; };
SomethingBooleanCallback callback;
public:
void UseCallback(SomethingBooleanCallback a) {callback = a;}
bool CallCallback() {return ((ChildCrtp *)this->*callback)();}
};
template<typename ChildCrtp>
class SpecializedInterfaceA : public MotherInterface<ChildCrtp>
{
public:
/// methods to be overridden in child methods where the callbacks need to be bound
virtual int GetValue (void) const = 0;
protected:
///another helper methods
bool IsPositive(void) { return (GetValue() > 0); };
bool IsNegative(void) { return (GetValue() < 0); };
bool IsEven(void) { return ((GetValue() % 2) == 0); };
bool IsOdd(void) { return ((GetValue() % 2) == 1); };
};
template<typename ChildCrtp>
class ChildA1 : public SpecializedInterfaceA<ChildCrtp>
{
public:
//implements the interface
virtual int GetValue (void) const final override { return value;} ;
//bind the interfaces' callback by a reference to the object "isPositive", which contains a pointer to the desired method and a pointer to the object that owns the method)
void BindPositive(void) { this->UseCallback(&ChildA1::IsPositive); };
private:
//an attribute
int value;
};
答案 2 :(得分:0)
这里是固定版本。
#include <iostream>
#include <stdint.h>
using namespace std;
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)
{
return new 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;
}
PS:该代码泄漏了指向回调的指针,因此您需要添加代码以正确处理它。
答案 3 :(得分:0)
此解决方案受Jarod42的回答启发,可以编译和工作。
将MotherA的属性x_
更改为null
,negative
和positive
并检查结果。
#include <iostream>
#include <stdint.h>
using namespace std;
static constexpr int STORE_SIZE = 4;
void* operator new(size_t size)
{
cout << "ERROR HEAP USED" << endl;
}
template<typename T, size_t storeSize>
class CallbackStore
{
public:
CallbackStore() : that_(nullptr) {};
CallbackStore(T* that) : that_(that) {};
using CallbackCondition = bool (*) (T*);
using CallbackAction = void (*) (T*,int);
struct Step
{
CallbackCondition pCallbackCondition;
CallbackAction pCallbackAction;
};
void setStep(int stepId,CallbackCondition pCallbackCondition, CallbackAction pCallbackAction)
{
if(stepId<storeSize)
{
store[stepId].pCallbackCondition = pCallbackCondition;
store[stepId].pCallbackAction = pCallbackAction;
}
else
{
cout << "pointer error" << endl;
}
}
void callStep(int stepId, int param)
{
if((stepId<storeSize) &&
(store[stepId].pCallbackCondition != nullptr) &&
(store[stepId].pCallbackAction != nullptr) &&
(that_ != nullptr))
{
bool isActive = (*(store[stepId].pCallbackCondition))(that_);
if(isActive) {(*(store[stepId].pCallbackAction))(that_,param);}
}
else
{
cout << "pointer error" << endl;
}
}
Step store[storeSize];
T* that_;
};
template<typename Base>
class Interface : public Base // interface
{
public:
static bool True(Base* baseInstance)
{
return true;
}
static bool IsNegative(Base* baseInstance)
{
return ((static_cast<Base*>(baseInstance))->getValue() < 0);
}
static bool IsNull(Base* baseInstance)
{
return ((static_cast<Base*>(baseInstance))->getValue() == 0);
}
static void PrintValue(Base* baseInstance, int value)
{
cout << "print this value : " << value << "." << endl;
}
};
class MotherA
{
public:
int getValue() { return x_; }
void setValue(int x) { x_ = x; }
private:
int x_ = -3;
};
class ChildA : public Interface<MotherA>, public CallbackStore<MotherA, STORE_SIZE>
{
public:
ChildA():Interface<MotherA>(), CallbackStore<MotherA, STORE_SIZE>(this){};
void setup()
{
setStep(0, &Interface::IsNegative, &Interface::PrintValue );
setStep(1, &Interface::IsNull, &Interface::PrintValue );
setStep(2, &Interface::IsNull, &Interface::PrintValue );
setStep(3, &Interface::True, &Interface::PrintValue );
}
};
int main()
{
ChildA c;
c.setup();
for(int i = 0; i < STORE_SIZE; i++)
{
c.callStep(i,8);
}
// shall print "print this value : 8." 3 times if x_ is null, twice if x_ is negative.
}