You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现支持错误检查与返回值获取的C++函数调用宏?

C++ errno类函数调用校验封装方案

C++开发中经常需要调用一批行为逻辑相似的函数:这类函数执行失败时会返回负值,同时设置errno变量记录错误详情。为了避免重复编写冗余的返回值校验逻辑,通常会把校验逻辑封装为宏,原有实现如下(已修正原代码的语法错误):

#define CHECKED_CALL( func, ... ) \
    do {\
        auto ret = func( __VA_ARGS__ );\
        if( ret < 0 ) {\
            std::cerr << #func "() failed with ret " << ret << " errno " << errno << std::endl;\
            throw std::runtime_error( #func "() failed" );\
         }\
    } while(false)

这个宏的基础使用方式非常简便:

CHECKED_CALL( func1, 1, 2, 3 );
CHECKED_CALL( func2, "foobar" );

但原有宏存在使用局限:当需要在调用成功时获取函数的返回值,例如编写如下代码时,原有宏无法支持:

auto r = CHECKED_CALL( func3, 1.5 );

虽然可以额外编写一个支持返回值的新宏,但完全可以用更低成本的方案实现双场景兼容,同时避免维护多套冗余逻辑,具体可以选择以下两种实现:

方案1:改进宏实现,兼容两种调用场景

直接将原有do-while语句块替换为编译器广泛支持的语句表达式,即可让宏同时支持独立语句调用和返回值赋值:

#define CHECKED_CALL(func, ...) \
    ({\
        auto ret = func(__VA_ARGS__);\
        if (ret < 0) {\
            std::cerr << #func "() failed with ret " << ret << " errno " << errno << std::endl;\
            throw std::runtime_error(#func "() failed");\
        }\
        ret;\
    })

这个实现的特点:

  • 完全兼容原有无返回值的调用写法,不需要修改存量代码
  • 支持直接赋值获取成功时的返回值
  • 不需要返回值时,编译器会自动优化掉未使用的返回值,不会触发未使用变量/返回值的编译警告
    注意:语句表达式属于编译器扩展,GCC、Clang、MSVC 2022及以上版本均已支持,若需要严格遵循标准C++,可以使用下面的非宏模板方案。

方案2:标准C++兼容的非宏模板实现

基于C++11及以上版本的可变参数模板和完美转发特性,可以完全脱离宏实现零开销的校验逻辑,不会触发任何编译警告:

#include <stdexcept>
#include <iostream>
#include <cerrno>
#include <type_traits>
#include <utility>
#include <string>

template <typename Func, typename... Args>
auto checked_call(const char* func_name, Func&& func, Args&&... args) 
    -> std::invoke_result_t<Func, Args...>
{
    auto ret = std::forward<Func>(func)(std::forward<Args>(args)...);
    if (ret < 0) {
        std::cerr << func_name << "() failed with ret " << ret << " errno " << errno << std::endl;
        throw std::runtime_error(std::string(func_name) + "() failed");
    }
    return ret;
}

// 仅保留极轻量的宏做函数名字符串化,核心逻辑全部复用模板实现
#define CHECKED_CALL(func, ...) checked_call(#func, func, __VA_ARGS__)

这个实现的特点:

  • 调用方式和原有宏完全一致,存量代码无需修改
  • 同时支持无返回值调用和返回值赋值场景
  • 完美转发参数和返回值,没有额外运行时开销
  • 核心逻辑用普通C++代码编写,避免了宏的变量名冲突、运算符优先级等常见问题
  • 不需要返回值时编译器会自动优化丢弃返回值,无编译警告
  • 兼容所有C++11及以上标准版本,不依赖任何编译器扩展

内容的提问来源于stack exchange,提问作者Slava

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 11:15:30