C++ Can a c++;模板模式取代了不断增长的联盟?
我有一个简单的类,它允许一个中断(或其他例程)来安排一个函数在主循环代码的下一个过程中运行。这是通过使用C++ Can a c++;模板模式取代了不断增长的联盟?,c++,templates,C++,Templates,我有一个简单的类,它允许一个中断(或其他例程)来安排一个函数在主循环代码的下一个过程中运行。这是通过使用联合来描述不同的可能参数模式来实现的 按原样,添加新类型的参数模式需要 为图案添加typedef 向联合中添加一个struct,以表示参数 添加一个adddoore声明和函数来处理add 更新循环代码切换语句以处理新的模式类型 每一个新的参数模式都需要做一点工作。我正在学习模板,想知道这个类是否可以重写为使用模板来简化添加额外的参数模式?如果是这样的话,模式是否也可以扩展以允许不同数量的参数
联合来描述不同的可能参数模式来实现的
按原样,添加新类型的参数模式需要
为图案添加typedef
向联合中添加一个struct
,以表示参数
添加一个adddoore
声明和函数来处理add
更新循环
代码切换语句以处理新的模式类型
每一个新的参数模式都需要做一点工作。我正在学习模板,想知道这个类是否可以重写为使用模板来简化添加额外的参数模式?如果是这样的话,模式是否也可以扩展以允许不同数量的参数
typedef void (*looper_runner1)(uint32_t arg1, uint16_t arg2);
typedef void (*looper_runner2)(uint8_t *arg1, uint16_t arg2);
struct LoopDooer
{
uint16_t type;
union {
struct
{
uint32_t arg1;
uint16_t arg2;
looper_runner1 fn;
} type1;
struct
{
uint8_t *arg1;
uint16_t arg2;
looper_runner2 fn;
} type2;
} dooer;
};
class Looper
{
public:
Looper();
bool addDooer(looper_runner1 fn, uint32_t arg1, uint16_t arg2);
bool addDooer(looper_runner2 fn, uint8_t *arg1, uint16_t arg2);
void loop();
private:
/* ... actual methods not relevant to question */
};
bool Looper::addDooer(looper_runner1 fn, uint32_t arg1, uint16_t arg2)
{
LoopDooer *p = new LoopDooer();
p->type = 1;
p->dooer.type1.fn = fn;
p->dooer.type1.arg1 = arg1;
p->dooer.type1.arg2 = arg2;
return _add(p);
}
bool Looper::addDooer(looper_runner2 fn, uint8_t *arg1, uint16_t arg2)
{
LoopDooer *p = new LoopDooer();
p->type = 2;
p->dooer.type2.fn = fn;
p->dooer.type2.arg1 = arg1;
p->dooer.type2.arg2 = arg2;
return _add(p);
}
// To be called from main loop
void Looper::loop()
{
LoopDooer *p;
/* some code removed that just gets next LoopDooer into pointer p */
// Do it
switch (p->type)
{
case 1:
p->dooer.type1.fn(p->dooer.type1.arg1, p->dooer.type1.arg2);
break;
case 2:
p->dooer.type2.fn(p->dooer.type2.arg1, p->dooer.type2.arg2);
break;
}
// Delete it
delete p;
}
您在这里尝试的所有操作都可以通过std::function
和lambdas直接完成。对于任意参数类型,它们实现您想要的所有逻辑
#include<functional>
using LoopDooer = std::function<void()>;
template<typename F, typename... Args>
bool Looper::addDooer(F f, Args&&... args) {
return _add([=]{ f(args...); });
}
void Looper::loop() {
LoopDooer dooer = /* extract LoopDoer from container */;
dooer();
}
#包括
使用loopdoore=std::函数;
模板
bool Looper::adddoorer(F,Args&&…Args){
返回_add([=]{f(args…;});
}
void Looper::loop(){
loopdooter=/*从容器中提取LoopDoer*/;
doore();
}
还要注意,使用new
/delete
手动管理内存是个坏主意。至少要使用std::unqiue_ptr
,但实际上根本不需要任何动态分配。您使用的任何容器都可能直接包含loopdoore
s。您在这里尝试的所有操作都可以通过std::function
和lambdas直接完成。对于任意参数类型,它们实现您想要的所有逻辑
#include<functional>
using LoopDooer = std::function<void()>;
template<typename F, typename... Args>
bool Looper::addDooer(F f, Args&&... args) {
return _add([=]{ f(args...); });
}
void Looper::loop() {
LoopDooer dooer = /* extract LoopDoer from container */;
dooer();
}
#包括
使用loopdoore=std::函数;
模板
bool Looper::adddoorer(F,Args&&…Args){
返回_add([=]{f(args…;});
}
void Looper::loop(){
loopdooter=/*从容器中提取LoopDoer*/;
doore();
}
还要注意,使用new
/delete
手动管理内存是个坏主意。至少要使用std::unqiue_ptr
,但实际上根本不需要任何动态分配。无论您使用什么容器,都应该直接包含loopdoore
s。我不知道模板是正确的方法。它们用于操作相同但数据类型不同的情况。您应该考虑查看STD::BIN,在不添加操作的情况下添加新类型是基于继承的多态性的经典用例。我会从那里开始寻找灵感。有一些方法可以让它比添加一个全新的派生类更简洁,但它们的想法还是一样的,我不知道模板是正确的方法。它们用于操作相同但数据类型不同的情况。您应该考虑查看STD::BIN,在不添加操作的情况下添加新类型是基于继承的多态性的经典用例。我会从那里开始寻找灵感。有一些方法可以使它比添加一个全新的派生类更简洁,但它们仍然有相同的想法。太好了,谢谢!我怀疑会有更容易的事情发生。我学习和写了很多C++之前lambdas和当它几乎没有模板。从那以后(25年多了?)我一直在用其他更高级的语言写作。现在我必须回到C++来为ARDUINO编写一些代码,但是我用以前的方式写在我的脑子里。很高兴有一个开始学习的指针@D'AtAgAnEngEngEngBrbasa是的,较新的C++特性使编写更高级抽象变得更容易。还要注意,std::function
并没有真正实现您的方法。它使用类型擦除。然而,自C++17以来,您所使用的联合方法也在标准库中实现为std::variant
,因此实际上没有任何理由再手动编写此类联合。Lambda在很大程度上只是句法上的糖。您可以编写一个模板函子。(但这需要一个完整的类定义,而lambda可以写在表达式中。)太好了,谢谢!我怀疑会有更容易的事情发生。我学习和写了很多C++之前lambdas和当它几乎没有模板。从那以后(25年多了?)我一直在用其他更高级的语言写作。现在我必须回到C++来为ARDUINO编写一些代码,但是我用以前的方式写在我的脑子里。很高兴有一个开始学习的指针@D'AtAgAnEngEngEngBrbasa是的,较新的C++特性使编写更高级抽象变得更容易。还要注意,std::function
并没有真正实现您的方法。它使用类型擦除。然而,自C++17以来,您所使用的联合方法也在标准库中实现为std::variant
,因此实际上没有任何理由再手动编写此类联合。Lambda在很大程度上只是句法上的糖。您可以编写一个模板函子。(但这需要一个完整的类定义,而lambda可以写在表达式中。)