gpt4 book ai didi

c++ - 是否可以只使用 function-member 属性创建回调接口(interface)?

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:02:33 26 4
gpt4 key购买 nike

上下文:

不使用堆的嵌入式 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;
}

这个设计有几个问题:

  • 回调对象存储了两次
  • 接口(interface)具有非函数成员属性:回调。
  • 写库很痛苦,因为你需要写方法和回调,而且你必须在所有使用你的回调的类中定义它!
  • 可能不适合使用 CRTP。我为什么要使用 CRTP?请参阅[此处]。(How to define a template specific type that can be inherited?)

解决方案?

这可能吗?

我走在正确的轨道上吗?如果不是,什么是正确的工具?

我用谷歌搜索并找到了几个轨道,但仍然不知道如何去做:

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++ 中是不合法的。

这个回调接口(interface)的问题是它需要一个指针来存储对象“FooGenericCallback”,它不能是“FooSpecificCallback”,因为对象类型在母类中是未知的。

3) 将回调实现为接口(interface)的其他方式

how to implement callback as an interface

但解决方案仍然使用对象来存储接口(interface)(或接口(interface)的子级)中的函数成员。

4) Lambdas...

我知道 lambda 会简化我的生活,事实上,我首先使用 lambda 做到了,代码大小从 60kB 增加了一倍到 120kB(!),因为 lambda 的存储方式:在 std::function 中。答案不应该是“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

关于c++ - 是否可以只使用 function-member 属性创建回调接口(interface)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56932216/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com