c++macrosc-preprocessor

Is there a way to conditionally include a header or import a module depending on a switch/flag?


I've tried:

#ifdef USE_CPP20_MODULES
#define IMPORT_OR_INCLUDE(module_name, include_filepath) \
import module_name;
#else
#define IMPORT_OR_INCLUDE(module_name, include_filepath) \
#include include_filepath
#endif

But none of the compilers compiler it:

Clang:

    Output of x86-64 clang 19.1.0 (Compiler #1)

<source>:6:2: error: '#' is not followed by a macro parameter
    6 | #include include_filepath
      |  ^

GCC:

<source>:5:56: error: '#' is not followed by a macro parameter
    5 | #define IMPORT_OR_INCLUDE(module_name, include_filepath) \

I do not understand why the preprocessor fails.
I'm guessing you can't use #include as the definition/replacement of a macro?


Solution

  • # has special meaning for the preprocessor. It's the stringize operator.

    [cpp.stringize]:

    15.6.3 The # operator

    1. Each # preprocessing token in the replacement list for a function-like macro shall be followed by a parameter as the next preprocessing token in the replacement list.

    Since include is not a parameter in the function-like macro, substitution fails.

    You can't add a parameter taking #include as an argument either:

    [cpp.replace]:

    If there are sequences of preprocessing tokens within the list of arguments that would otherwise act as preprocessing directives, the behavior is undefined.


    You could put all imports for this file in one header and all the includes in a different header and then #include the the one you want according to USE_CPP20_MODULES:

    #ifdef USE_CPP20_MODULES
    #define HEADER_NAME "tu_imports.h"
    #else
    #define HEADER_NAME "tu_includes.h"
    #endif
    #include HEADER_NAME
    

    Or just:

    #ifdef USE_CPP20_MODULES
    #include "tu_imports.h"
    #else
    #include "tu_includes.h"
    #endif
    

    Or simply do it directly where you need it:

    #ifdef USE_CPP20_MODULES
    import module_a;
    import module_b;
    #else
    #include "a.h"
    #include "b.h"
    #endif