如何将操作委托给函数返回

How to delegate an action to function return?

本文关键字:函数 返回 操作      更新时间:2023-10-16

问题

我有以下简单的情况突然出现在各地。大量请求带着这样的功能签名到达设备:

Err execute( const ICommandContext &context, 
const RoutineArguments &arguments, 
RoutineResults &results)

本质上有一个请求处理服务器,它将调用此函数。执行具有这些签名的各种请求类型的函数。在出现错误的情况下,我们有两条返回路径。

  1. Err输出类型(认为它等效于int(,用于通知服务器或系统出现了与系统有关的问题,而不是请求。在处理用户请求之前,它总是被排序在函数的顶部
  2. CCD_ 3提供了CCD_ 4功能,可用于向客户端返回请求的失败信息

由于这个原因,我们弹出了很多这种类型的代码:

// Failure due to request
Err error = someFunctionCall(clientInput);
if (!error.success()) {
results.setStatus(error); // Inform the client of the error
return SUCCESS; // Inform the system that we are all good
}

我们有一个特定的请求类型,它有大约15参数,这些参数在系统中传入和传出。我们在概念上需要这个if error do集合中的15个,这似乎是浪费。如果我们需要经历并改变我们返回的方式,也很容易出错我们如何有效地委托setStatus,并返回到只需要在函数中发生一次的少量代码

宏观解决方案

c系统可以用宏来解决这个问题,比如:

#define M_InitTry Err error
#define M_Try(statement) if (!(error = statement).success()) { goto catch_lab; }
#define M_Catch catch_lab: if (!error.successs())
#define M_Return return error

使用方式如下:

Err execute( const ICommandContext &context, ...) {
M_InitTry;
...
M_Try(someFunctionCall(clientInput));
M_Try(someFunctionCall(otherClientInput));
...
M_Catch {
// Other specific actions for dealing with the return.
results.setStatus(error);
error = SUCCESS;
}
M_Return;
}

这很好地清理了代码,但对于goto来说不是特别好。如果定义goto可能跳过的变量,则会导致问题。

委派解决方案

我正试图想出一个更C++的代理,所以我认为RAII类型的代理可能会有所帮助。类似于:

class DelegateToFunctionEnd {
typedef std::function<void(void)> EndFunction; 
public: 
DelegateToFunctionEnd(EndFunction endFunction) : callAtEnd(endFunction) { }
~DelegateToFunctionEnd() {
callAtEnd();
}
private:         
EndFunction callAtEnd;
};

很简单,它通过在析构函数中实现操作来完成操作的委托,直到函数返回。你可以这样使用它:

Err execute( const ICommandContext &context, ...) {
Err error;
DelegateToFunctionEnd del(std::bind(&RoutineResults::setStatus, &results, std::cref(error)));
error = someFunctionCall(clientInput));
if (error) return SUCCESS;
...
}

活生生的例子。这个解决方案看起来不错,但有几个问题:

  1. 目前还不清楚发生了什么
  2. 正确设置错误更容易出错
  3. 您仍然需要大量的if语句来处理返回
  4. 配置终止操作的能力不太好
  5. 如果用户在函数返回时没有仔细考虑物品的销毁顺序,则会有危险

更好的解决方案

这一定是一个经常出现的问题。有没有一个通用的解决方案可以提供该集合的干净委托并返回类型的操作?


我有一些不幸的限制。不要让这些阻止你回答,因为这可能对未来的人有帮助

  1. 我正在开发一个c++03有限系统。我们有boost,但没有c++11
  2. 嵌入式系统和我们有关于异常和内存分配的愚蠢规则

如果错误状态代码很麻烦,您应该考虑使用异常。也就是说,更改函数的API

  • 所以他们保证会成功
  • 发生故障时抛出合适的std::exception

如果您这样做,就不可能"忘记"检查状态代码。如果您选择不处理错误情况,那么低级代码引发的异常会自动向上渗透。如果,您只需要catch一个低级别异常

  • 发生错误时,您需要进行一些手动回滚或解除分配,RAII不切实际。在这种情况下,您将重新考虑表达式
  • 您希望使用抛出的嵌套异常将低级异常消息或异常类型转换为高级消息

也许,您可以将语句写成数组,类似于:

Err execute( const ICommandContext &context, ...)
{
const boost::function<Err()> functions[] = {
boost::bind(&someFunctionCall, std::ref(clientInput)),
boost::bind(&someFunctionCall, std::ref(otherClientInput)),
// ...
};
for (std::size_t i = 0; i != sizeof(functions) / sizeof(functions[0]); ++i) {
Err err = functions[i]();
if (!err.successs()) {
results.setStatus(err);
return SUCCESS;
}
}
return SUCCESS;
}

如果你用不同的语句多次这样做,您可以创建

Err execute_functions(const ICommandContext &context, std::function<Err()> functions);

根据您的需要,也可以提供OnError等其他入口点。

拆分函数。

内部函数根据用户输入返回错误代码;outer将其转换为客户端错误,并且只返回服务器端错误。

内部功能包含:

if(Err error = someFunctionCall(clientInput))
return error;

重复。外部有中继到客户端的错误代码,但只有一次。

Err只需要一个运算符bool。如果它不能拥有它,请创建一个转换为Err或从Err转换为具有运算符bool的类型。

你能给error添加一个方法来检查etc并返回一个bool吗。

if(!someFunctionCall(clientInput).handleSuccess(results))
{
return SUCCESS;
}