4


I defined following two function macro to check exit flag in my thread class.

//use this in run()
#define CHECK_EXIT  if( exitFlag_ ) {\
    //do something\
    return;\
}\

//use this in function
#define CHECK_EXIT_IN_FUNC  if( exitFlag_ ) {\
    //do something\
    return false;\
}\

I had to define them separately because returning value is different.
Can I define it in one macro?
I googled, but couldn't find answer.
Thanks for any advice.

Winter Singha
  • 151
  • 1
  • 6
  • 16

3 Answers3

4

You can use a variadic macro. Pass in nothing if you don't want to return anything after the check.

#define CHECK_EXIT(...) CHECK_EXIT_(_, ##__VA_ARGS__)
#define CHECK_EXIT_(...) CHECK_EXIT_X(__VA_ARGS__, _1, _0)(__VA_ARGS__)
#define CHECK_EXIT_X(_0, _1, X, ...) CHECK_EXIT ## X
#define CHECK_EXIT_0(_) do if (exit_flag_) { /*...*/ return; } while(0)
#define CHECK_EXIT_1(_, R) do if (exit_flag_) { /*...*/ return (R); } while(0)

void test_0 () {
    bool exit_flag_ = true;
    CHECK_EXIT();
}

int test_1 () {
    bool exit_flag_ = true;
    CHECK_EXIT(0);
    return 1;
}

I used a very simplified version of the argument counting trick described in a different answer. I am able to simplify it because I rely on a GCC extension (##__VA_ARGS__) to remove the trailing comma if the variable arguments expansion is empty. Use the full blown version if you are not using a compiler that understands this GCC extension.

Community
  • 1
  • 1
jxh
  • 69,070
  • 8
  • 110
  • 193
3

I'm not sure how you can do it "in one macro" for functions of different types, unless you opt to specify the actual return value from outside.

If you don't mind doing that, then you can take advantage of the fact that in C++ (but not in C) you can return void expressions from void functions. For example, you can return (void) 0 as a "void" value. I.e. you can do

#define CHECK_EXIT_IN_FUNC(ret)  if( exitFlag_ ) {\
    //do something\
    return (ret);\
}

and invoke it as CHECK_EXIT_IN_FUNC(false) or CHECK_EXIT_IN_FUNC((void) 0) depending on the type of the function.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
3

The C++11 rules for return types create a bit of an interesting case:

A return statement with an expression of non-void type can be used only in functions returning a value; the value of the expression is returned to the caller of the function. The value of the expression is implicitly converted to the return type of the function in which it appears.

and later

A return statement with an expression of type void can be used only in functions with a return type of cv void; the expression is evaluated just before the function returns to its caller.

It seemed natural to create a type that would implicitly convert to void. Unfortunately the expression has this custom type, which counts as non-void type, and is rejected.

struct does_not_work
{
    operator void() const {}
    template<typename T> operator T() const { return T{}; }
};

I'm not sure whether I would support rewording the rule to allow types that implicitly convert to the return type even if that return type is void.

Similarly, this is rejected:

return {};

(but so is void{})

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720