【问题标题】:Wrap a C API function returning pointer into macro call将返回指针的 C API 函数包装到宏调用中
【发布时间】:2016-11-17 21:44:09
【问题描述】:

我正在尝试将在某些情况下返回 int 的 C API 函数和在其他情况下返回的指针包装到宏中,以检查条件并提供诊断并在发生错误时抛出异常。对于返回 int 的函数,这很简单,因为我不需要 int

#define CALL_INT( name, ... ) do { \
        if( !name( __VA_ARGS__ ) ) throw std::runtime_error( #name " failed" );
     } while(0)

  // using it
  CALL_INT( foo, arg );

但是对于返回指针的函数,它并不那么简单,因为我需要对照nullptr 检查该指针,然后将其分配给我的指针。那么是否可以编写类似的宏,所以这个表达式可以工作:

auto ptr = CALL_PTR( foobar, arg1, arg2 );

即它会生成代码,调用foobar( arg1, arg2 ) 对照nullptr 检查结果,如果没有发生错误,则使其可用于赋值。

【问题讨论】:

  • 为什么要这样做而不是制作模板包装器?
  • @krzaq 模板包装器无法字符串化函数名
  • 仅使用宏将函数名传递给模板化包装器的解决方案会让您满意吗?
  • @krzaq 是的,当然,无论如何你应该提供这个答案,因为它可能对其他人有用
  • 为什么不VERIFY( bob = name( a , b , c ) )

标签: c++ c++11 c-preprocessor


【解决方案1】:

真正的解决方案是:不要使用宏。只需写下你想做的内联。你和其他人,以后会感谢你自己的。


文字解决方案是立即调用 lambda:

#define MAYBE_THROW(f, ...)                                   \
    [&]{                                                      \
        auto _result = f(__VA_ARGS__);                        \
        if (!_result) throw std::runtime_error(#f " failed"); \
        return _result;                                       \
    }()

MAYBE_THROW(foo, arg);
auto ptr = MAYBE_THROW(foobar, arg1, arg2);

【讨论】:

  • 内联函数的问题 - 每次调用我都必须一次又一次地复制粘贴代码,这会导致所有问题。
  • 有效!只需删除前导分号。为什么要在这个 lambda 中捕获?
  • @Slava 将参数传递给需要捕获的api函数
  • @krzaq 它在没有捕获的情况下对我来说编译得很好,嗯,也许我做错了什么
  • @slava 您是否将文字传递给宏?它们不需要被捕获,但变量必须是
【解决方案2】:

魔法越少越好

#define VERIFY( ... ) \
  [&](){
     auto r = __VA_ARGS__;
     if (!r) throw std::runtime_error( #__VA_ARGS__ " failed" );
     return r;
  }()

这需要一个表达式。它运行它。然后它会对其进行测试,如果失败则抛出。

如果失败,则在 throw 中包含整个表达式。

然后它返回它。

没有那么神奇,VERIFY(bob) 只是在做bob。你可以这样做

int x = VERIFY( call(a,b,c) );

VERIFY( y = call(a,b,c) );

或其他。主要代码运行在那里;失败时只有断言包装器丢失。

VERIFY 也称为宏,通常执行此操作。

【讨论】:

    猜你喜欢
    • 2010-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-25
    • 1970-01-01
    • 2015-08-05
    相关资源
    最近更新 更多