可以使用仅功能成员属性进行回调界面
Is that possible to make a callback interface with only function-member attribute?
上下文:
嵌入式C 没有堆的使用。
我想掌握我的代码(包括大小(,因此我不想使用标准lib,例如std :: function。
1st方法:
让我们使用CRTP的修改版本:
以此示例(这是我代码的简化版本(注意:我回调的方法可能具有这些签名: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;
}
此设计有几个问题:
- 回调对象两次存储
- 接口具有非函数成员属性:回调。
- 写一个lib是很痛苦的,因为您需要编写方法和回调,并且必须在使用您的回调的所有类中定义它!
- 也许使用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 中是不合法的。
此回调接口的问题是它需要一个指针来存储对象" foogogenericCallback",这不能是" foospecificcallback",因为母亲类是不知道的对象类型。
3(其他方法将回调作为接口
如何将回调作为接口
实现但是该解决方案仍然使用对象将函数成员存储在接口(或接口的孩子(中。
4(lambdas ...
我知道Lambdas会简化我的生活,的确,我首先使用Lambdas进行了工作,并且代码大小从60kb增加到120KB(!(,因为Lambdas的存储方式:在STD ::功能中。答案不应该是" lambda":(
我可能已经过度简化了您的需求,但是有什么问题:
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;
}
demo
我仍然不确定我是否正确理解您的意图。但是,遵循编码没有错误的编译,尽管我没有进一步测试:
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;
};
这是固定版本。
#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:此代码将指针泄漏为回调,因此您需要添加代码才能正确处理。
此解决方案,灵感来自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.
}
- 架构决策:返回std::future还是提供回调
- 正在为Xtensa simcall函数编写回调函数
- 如何在C++中使用非静态成员函数作为回调函数
- FLTK:按下哪个按钮 - 将数字传递给按钮的回调 (lambda)
- 在简单示例中,Python3 + ctypes 回调会导致内存泄漏
- 用于在回调中调用解析器的设计模式
- 如何使用C++对象的成员函数作为 C 样式回调?
- Java从C++回调到C++回调
- 如何将成员函数作为回调参数传递给需要"typedef-ed"自由函数指针的函数?
- 从不同的 cpp 调用回调函数会导致bad_function_call
- pcap_handler回调仅在使用 NPCAP v0.9991 时包含空数据包
- 不带轮询的 SDL2 事件回调
- C++存储带有可变参数的回调
- 如何使用 Node-addon-API 实现 node-nan 回调
- 处理影响跨不同线程共享对象的定时回调的最佳方法是什么?
- 访问类C++ C 样式回调
- 处理类内的回调时,必须调用对非静态成员函数的引用
- 如果 C 函数仍然可以间接执行(通过回调函数),那么将它声明为静态函数是否是一种不好的做法?
- 在C++中实现回调
- 可以使用仅功能成员属性进行回调界面