Sharing a couple macros I use

I found my self constantly checking many objects to see if they are valid so I started using these two macros in my code. [FONT=Courier New]AllValid(…) and [FONT=Courier New]AnyInvalid(…). Essentially I turned all statements like this:



if(IsValid(Obj) && IsValid(OtherObj)) {
    Obj->DoThing();
    OtherObj->DoOtherThings(Obj);
}

To something like this:



if(AllValid(Obj, OtherObj)) {
    Obj->DoThing();
    OtherObj->DoOtherThings(Obj);
}

You could also do this at the top of a function if it requires certain objects to be valid.



if(AnyInvalid(Obj1, Obj2, Obj3)) {
    return;
}


The valid checking is done in sequential order so you can use the previous object in the next argument.



UWorld* world;
if(AnyInvalid(SomeActor, world = SomeActor->GetWorld())) {
    return;
}


Here’s the source:


#define EXPAND(x) x

#define CAT( A, B ) A ## B
#define SELECT( NAME, NUM ) CAT( NAME ## _, NUM )

#define GET_COUNT( _1, _2, _3, _4, _5, _6, COUNT, ... ) COUNT
#define VA_SIZE( ... ) EXPAND(GET_COUNT( __VA_ARGS__, 6, 5, 4, 3, 2, 1 ))

#define VA_SELECT( NAME, ... ) EXPAND(SELECT( NAME, VA_SIZE(__VA_ARGS__) )(__VA_ARGS__))

#define AllValid( ... ) (VA_SELECT( AllValidArg, __VA_ARGS__ ))
#define AllValidArg_1(_obj1) IsValid(_obj1)
#define AllValidArg_2(_obj1, _obj2) AllValidArg_1(_obj1) && IsValid(_obj2) 
#define AllValidArg_3(_obj1, _obj2, _obj3) AllValidArg_2(_obj1, _obj2) && IsValid(_obj3) 
#define AllValidArg_4(_obj1, _obj2, _obj3, _obj4) AllValidArg_3(_obj1, _obj2, _obj3) && IsValid(_obj4)
#define AllValidArg_5(_obj1, _obj2, _obj3, _obj4, _obj5) AllValidArg_4(_obj1, _obj2, _obj3, _obj4) && IsValid(_obj5)
#define AllValidArg_6(_obj1, _obj2, _obj3, _obj4, _obj5, _obj6) AllValidArg_5(_obj1, _obj2, _obj3, _obj4, _obj5) && IsValid(_obj6)

#define AnyInvalid( ... ) (VA_SELECT( AnyInvalidArg, __VA_ARGS__ ))
#define AnyInvalidArg_1( _obj1 ) !IsValid(_obj1)
#define AnyInvalidArg_2( _obj1, _obj2 ) AnyInvalidArg_1(_obj1) || !IsValid(_obj2) 
#define AnyInvalidArg_3(_obj1, _obj2, _obj3) AnyInvalidArg_2(_obj1, _obj2) || !IsValid(_obj3) 
#define AnyInvalidArg_4(_obj1, _obj2, _obj3, _obj4) AnyInvalidArg_3(_obj1, _obj2, _obj3) || !IsValid(_obj4)
#define AnyInvalidArg_5(_obj1, _obj2, _obj3, _obj4, _obj5) AnyInvalidArg_4(_obj1, _obj2, _obj3, _obj4) || !IsValid(_obj5)
#define AnyInvalidArg_6(_obj1, _obj2, _obj3, _obj4, _obj5, _obj6) AnyInvalidArg_5(_obj1, _obj2, _obj3, _obj4, _obj5) || !IsValid(_obj6)

As you’ve probably noticed it only supports up to 6 arguments, but I’m sure if you need more you could easily add additional arguments if you’d like.

I believe once c++ fold expressions are more widely spread these could be turned into functions.

Another note: the EXPAND macro is used to fix an issue with msvc. It should be unneeded with a properly compliant compiler. (I haven’t tested this on anything else other than msvc)

1 Like