Skip to content

Instantly share code, notes, and snippets.

@kinchungwong
Created February 6, 2019 04:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kinchungwong/b194686a63e6a3c85513254c0f5dfaf4 to your computer and use it in GitHub Desktop.
Save kinchungwong/b194686a63e6a3c85513254c0f5dfaf4 to your computer and use it in GitHub Desktop.
Preprocessor macro trick detecting argument is exactly 0, NULL, or nullptr
Goal:
Define a preprocessor ("function-like") macro such that when the argument
is exactly one of: "0", "NULL", "nullptr" (without the quotes), the
macro is expanded to "1" (without the quotes), otherwise it should expand
to "0" instead.
References and useful information:
https://stackoverflow.com/questions/32399191/va-args-expansion-using-msvc
https://stackoverflow.com/questions/5134523/msvc-doesnt-expand-va-args-correctly
// Goal:
//
// Define a preprocessor ("function-like") macro such that when the argument
// is exactly one of: "0", "NULL", "nullptr" (without the quotes), the
// macro is expanded to "1" (without the quotes), otherwise it should expand
// to "0" instead.
//
// The following attempt is tested on
// Microsoft Visual Studio Community Edition 2017, Version 15.6.3
//
// This attempt contains a workaround for MSVC, therefore it will not work
// on other compilers unless modifications are made.
//
// To see preprocessor output. use /E option with MSVC compiler.
//
// Suggestion:
// (1) Turn off precompiled header for the cpp file containing this macro
// test code,
// (2) Don't put any C++ code other than preprocessor definitions in the
// test cpp file.
#define GET0(arg0, ...) arg0
#define GET1(arg0, arg1, ...) arg1
#define GET2(arg0, arg1, arg2, ...) arg2
// (This description is written by a novice, and may contain technical errors.)
//
// In Microsoft Visual C++, the expansion of __VA_ARGS__ is treated as one token.
// As a result, when __VA_ARGS__ is used in invoking another preprocessor macro,
// the expansion of __VA_ARGS__ will be used to populate exactly one input
// argument for the macro being invoked.
//
// Thus, for Microsoft Visual C++, the correct way to implement the
// re-evaluation macro is:
// #define RE_EVALUATE(x) x
// but not
// #define RE_EVALUATE(...) __VA_ARGS__
// if the argument is known to contain __VA_ARGS__.
//
// References
// https://stackoverflow.com/questions/32399191/va-args-expansion-using-msvc
// https://stackoverflow.com/questions/5134523/msvc-doesnt-expand-va-args-correctly
//
#define PRETREAT_VA_ARGS_MSVC(x) x
#define KNOWN_NULL(x) 0, 0
#define KNOWN_0(x) 0, 0
#define KNOWN_nullptr(x) 0, 0
#define GET2_MSVC(...) PRETREAT_VA_ARGS_MSVC(GET2(__VA_ARGS__))
#define IS_KNOWN(x) GET2_MSVC(KNOWN_##x(x), 1, 0)
#pragma message( IS_KNOWN(z) )
#pragma message( IS_KNOWN(imgproc) )
#pragma message( IS_KNOWN(std::cout) )
#pragma message( IS_KNOWN(0) )
#pragma message( IS_KNOWN(nullptr) )
#pragma message( IS_KNOWN(NULL) )
#if 0
// Preprocessor output
>#pragma message(0)
>#pragma message(0)
>#pragma message(0)
>#pragma message(1)
>#pragma message(1)
>#pragma message(1)
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment