Created
February 6, 2019 04:03
-
-
Save kinchungwong/b194686a63e6a3c85513254c0f5dfaf4 to your computer and use it in GitHub Desktop.
Preprocessor macro trick detecting argument is exactly 0, NULL, or nullptr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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