Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/132.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 泛型返回\u IF\u FALSE()宏?_C++_Macros - Fatal编程技术网

C++ 泛型返回\u IF\u FALSE()宏?

C++ 泛型返回\u IF\u FALSE()宏?,c++,macros,C++,Macros,我试图清理一些遗留代码,其中包含数百个函数,其主体如下所示: void functionWithSideEffect(Foo* foo) { if (foo) { // Use `foo' to warm the planet ... } } 显然,如果先决条件检查失败,则默认失败不是最好的主意,因此我想将其重构为: int functionWithSideEffect(Foo* foo) { RETURN_IF_FALSE(fo

我试图清理一些遗留代码,其中包含数百个函数,其主体如下所示:

void functionWithSideEffect(Foo* foo)
{
    if (foo)
    {
        // Use `foo' to warm the planet
        ...
    }
}
显然,如果先决条件检查失败,则默认失败不是最好的主意,因此我想将其重构为:

int functionWithSideEffect(Foo* foo)
{
    RETURN_IF_FALSE(foo != NULL, "foo is NULL in functionWithSideEffect!");

    // Use `foo' to warm the planet
    ...
}
对于不返回值的函数,以下宏似乎可以正常工作:

#define RETURN_IF_FALSE(cond, msg) \
  do { \
      if (!(cond)) { \
          LOG("%s\n", (msg)); \
          assert((cond)); \
      } \

      return; \
  } while(0)
并且它具有以下理想特性:

  • 它的用法简洁明了
  • 它不会默默地失败
  • 它将在调试版本中崩溃,但尝试在发布版本中继续
(不可否认,对于返回
void
的函数,在发布版本中的构建上当兵可能并不总是“可取的”。)

对于返回值的函数,此宏执行以下操作:

#define RETURN_VALUE_IF_FALSE(cond, msg, retval ) \
  do { \
      if (!(cond)) { \
          LOG("%s\n", (msg)); \
          assert((cond)); \
      } \
      return(retval); \
  } while(0)
我的问题是:是否可以编写一个
RETURN\IF\u FALSE
宏来处理
void
函数和返回值的函数?我坐下来尝试使用varargs宏,很快发现我不太擅长编写复杂的宏。我从这个测试项目开始:

#include <stdio.h>
#include <assert.h>

#define RETURN_IF_FALSE(cond, msg, ... ) \
  do { \
      if (!(cond)) { \
          fprintf(stderr, "%s\n", (msg)); \
          assert((cond)); \
      } \
      return (##__VA_ARGS__); \
  } while(0)


int main()
{
    RETURN_IF_FALSE(1 < 0, "1 is not less than 0!", -1);
    return 0;
}

(我认为允许设置“自由形式”消息字符串并不是那么必要/有用,所以我只是根据条件生成了一个罐装的消息字符串…

只需替换宏
返回(###VA_ARGS))的这一部分即可带有
返回参数我认为它应该做你想做的事情(假设你传递给返回值的不是一个复杂的表达式——如果是,你需要用括号预先包装参数)。

我成功了

#include <stdio.h>
#define RET_IF_FALSE(x, y, z) if (!x) { printf(y); return z; }


int a(int *p)
{
    RET_IF_FALSE(p, __FUNCTION__, 0);

    return *p;
}

void b(int *p)
{
    RET_IF_FALSE(p, __FUNCTION__, );
}


int main()
{
    int x;

    x = a(&x);
    b(&x);

    x = a(NULL);
    b(NULL);

    return 0;
}

对于其余的代码,同样适用于pedantic和-std=c99的gcc,以及在clang++和g++中使用-std=c++11的gcc。不确定MS编译器的功能是什么,因为它们对标准的支持有时不那么出色(而且我目前还没有Windows设置可供测试)。

为什么要这样做?如果指针为null,您将获得未定义的行为。如果您想让它尝试并继续运行,抛出一个异常,然后其他东西可以捕获它并尝试下一个操作。为什么要使用串联运算符
##
?如果是先决条件错误,只需中止/终止即可。不要回电话。调用代码已损坏。提示:只计算
cond
一次。为什么不在
if(foo)
语句中添加一个
else
子句,并对失败发出噪音?哇。真不敢相信我没试过,谢谢你的建议,它看起来很好用。如果我发现任何问题,我会在这里发表另一条评论,但现在,这让我得到了我想要的。此外,不要忘记执行重复数据消除者在其上述评论中建议的操作。您只需要计算
cond
一次。因此,将宏更改为仅
assert(0)如果执行if分支。我将
assert()
向上移动,以避免在晴天情况下对条件进行两次计算,但将条件保留在适当位置,以便在条件为
false
时,控制台中失败的断言的输出更容易理解。(无论如何,如果我们即将退出,我并不担心冗余的计算,但将其从主代码路径中移除确实是一个好主意。)
#define RETURN_IF_FALSE(cond, ... ) \
  do { \
      if (!(cond)) { \
          const char* msg = \
              "Pre-condition '" #cond "' not met, returning " #__VA_ARGS__ "..."; \
          LOG("%s\n", msg); \
          assert((cond)); \
          return __VA_ARGS__; \
      } \
  } while(0)
#include <stdio.h>
#define RET_IF_FALSE(x, y, z) if (!x) { printf(y); return z; }


int a(int *p)
{
    RET_IF_FALSE(p, __FUNCTION__, 0);

    return *p;
}

void b(int *p)
{
    RET_IF_FALSE(p, __FUNCTION__, );
}


int main()
{
    int x;

    x = a(&x);
    b(&x);

    x = a(NULL);
    b(NULL);

    return 0;
}
#define RET_IF_FALSE(x, y, ...) if (!x) { printf(y); return __VA_ARGS__; }