I have the following macro:
#define REFLECTABLE(...) \
REFLECTABLE_CONST(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__)==0, __VA_ARGS__)
I ran the pre-processor. It passes to REFLECTABLE_CONST 3==0 instead of 0 or false. In REFLECTABLE_CONST, I am using that value to simulate a conditional as described in this post. So, I need the pre-processor to pass a value. Is there a way to make pre-processor substitute things like 3==0 by false or 0?
I couldn't reproduce BOOST_PP_VARIADIC_SIZE being able to have a result of 0, but if you can, this should work:
#define IS_EMPTY_IMPL0 1
#define IS_EMPTY_IMPL1 0
#define IS_EMPTY_IMPL2 0
#define IS_EMPTY_IMPL3 0
#define IS_EMPTY_IMPL4 0
#define IS_EMPTY_IMPL5 0
#define IS_EMPTY_IMPL6 0
#define IS_EMPTY_IMPL7 0
#define IS_EMPTY_IMPL8 0
#define IS_EMPTY_IMPL9 0
#define IS_EMPTY(...) BOOST_PP_CAT(IS_EMPTY_IMPL, BOOST_PP_VARIADIC_SIZE(__VA_ARGS__))
#define REFLECTABLE(...) \
REFLECTABLE_CONST(IS_EMPTY(__VA_ARGS__), __VA_ARGS__)
Stumbled upon this solution. Just use this instead:
#define REFLECTABLE(...) \
REFLECTABLE_CONST(BOOST_PP_IS_EMPTY(__VA_ARGS__), __VA_ARGS__)
Related
I only found this related question, which isn't quite what I am looking for.
I used to have macros defined inside an #ifdef statement:
#ifdef DEBUG
# define PRINT_IF_DEBUGGING(format) printf(format);
# define PRINTF_IF_DEBUGGING(format, ...) printf(format, __VA_ARGS__);
#else
# define PRINT_IF_DEBUGGING(...)
# define PRINTF_IF_DEBUGGING(...)
#endif
Now, I want to do the inverse, to have the #ifdef statements inside the macros. Something like this:
#define PRINT_IF_DEBUGGING(format, ...) \
#if defined(DEBUG) print(format); #endif
#define PRINTF_IF_DEBUGGING(format, ...) \
#if defined(DEBUG) printf(format, __VA_ARGS__); #endif
However, I am having an issue using __VA_ARGS__ inside the #ifdef defined.
error: '#' is not followed by a macro parameter
#define PRINT_IF_DEBUGGING(format, ...)
error: '#' is not followed by a macro parameter
#define PRINTF_IF_DEBUGGING(format, ...)
warning: __VA_ARGS__ can only appear in the expansion of a C++11 variadic macro
#if defined(DEBUG) printf(format, __VA_ARGS__); #endif
Is this possible?
This should really be a comment, but I can't format that in a way that will allow me to say what I want to say, so I'm answering instead.
Anyway, just change this:
#if defined(DEBUG) print(format); #endif
to this:
#if defined(DEBUG)
print(format);
#endif
and so on, and that should fix it.
You can't use #ifdef inside of #define , so no, this is not possible. The first code you showed is the correct solution.
Using #ifdef inside of #define is not possible. But there are still ways you can detect wether or not a macro has been defined within a macro definition.
1. Solution
godbolt
#define CAT(a, b) CAT_IMPL(a, b)
#define CAT_IMPL(a, b) a ## b
#define IS_DEBUG_DEFINED() CHECK((CAT(CHECK_,DEBUG), 0, 1))
#define CHECK_DEBUG ~,~
#define CHECK(tup) CHECK_IMPL tup
#define CHECK_IMPL(a, b, c, ...) c
#define IIF(condition, true_value, false_value) CAT(IIF_,condition)(true_value, false_value)
#define IIF_0(true_value, false_value) false_value
#define IIF_1(true_value, false_value) true_value
#define PRINT_IF_DEBUGGING(format) IIF(IS_DEBUG_DEFINED(), PRINT_DEBUGGING, PRINT_NOT_DEBUGGING)(format)
// this will be used if DEBUG is defined:
#define PRINT_DEBUGGING(format) debugPrint(format)
// this will be used if DEBUG is NOT defined:
#define PRINT_NOT_DEBUGGING(format) print(format)
PRINT_IF_DEBUGGING(foo) will expand to:
if DEBUG is defined: debugPrint(foo)
if DEBUG is not defined: print(foo)
Example:
PRINT_IF_DEBUGGING("test1");
#define DEBUG
PRINT_IF_DEBUGGING("test2");
#undef DEBUG
PRINT_IF_DEBUGGING("test3");
would result in:
print("test1");
debugPrint("test2");
print("test3");
2. How IS_DEBUG_DEFINED() works
The fundamental trick behind this is to use concatenation - if the macro was defined it will be expanded, otherwise the token will be left unmodified by the preprocessor:
godbolt
#define CAT(a, b) CAT_IMPL(a, b)
#define CAT_IMPL(a, b) a ## b
// DEBUG NOT DEFINED:
CAT(CHECK_,DEBUG) // will expand to CHECK_DEBUG
// DEBUG DEFINED:
#define DEBUG 1234
CAT(CHECK_,DEBUG) // will expand to CHECK_1234
The first CAT will expand to CHECK_DEBUG, because DEBUG was not defined.
The second CAT however will expand to CHECK_1234, because DEBUG was defined and expanded to 1234 before the concatenation with CHECK_.
By defining a macro named CHECK_DEBUG we can change the result if the macro was not defined, e.g.:
godbolt
#define TEST CAT(CHECK_,DEBUG), 0, 1
#define CHECK_DEBUG ~,~
If DEBUG is not defined the result will be ~, ~, 0, 1 (4 comma-separated tokens)
If DEBUG is defined the result will be CHECK_, 0, 1 (3 comma-separated tokens)
Notice how we got 4 tokens in the first case, but only 3 tokens in the second.
Now all we need to do is take the 3rd token from that sequence (which will be 0 if DEBUG is not defined and 1 otherwise), for example with a simple macro that always returns the 3rd argument:
#define CHECK(a, b, c, ...) c
Putting it all together, this is what a full IS_DEBUG_DEFINED() could look like:
godbolt
#define CAT(a, b) CAT_IMPL(a, b)
#define CAT_IMPL(a, b) a ## b
#define IS_DEBUG_DEFINED() CHECK((CAT(CHECK_,DEBUG), 0, 1))
#define CHECK_DEBUG ~,~
#define CHECK(tup) CHECK_IMPL tup
#define CHECK_IMPL(a, b, c, ...) c
IS_DEBUG_DEFINED() will expand to 0 if DEBUG is not defined, and 1 if it is, e.g.:
IS_DEBUG_DEFINED() // -> 0
#define DEBUG
IS_DEBUG_DEFINED() // -> 1
#undef DEBUG
IS_DEBUG_DEFINED() // -> 0
With IS_DEBUG_DEFINED() you can then use a standard preprocessor IIF to change the behaviour of your macro depending on wether DEBUG is defined or not.
Example: godbolt
#define IIF(condition, true_value, false_value) CAT(IIF_,condition)(true_value, false_value)
#define IIF_0(true_value, false_value) false_value
#define IIF_1(true_value, false_value) true_value
#define PRINT_IF_DEBUGGING(format) IIF(IS_DEBUG_DEFINED(), PRINT_DEBUGGING, PRINT_NOT_DEBUGGING)(format)
// this will be used if DEBUG is defined:
#define PRINT_DEBUGGING(format) debugPrint(format)
// this will be used if DEBUG is NOT defined:
#define PRINT_NOT_DEBUGGING(format) print(format)
PRINT_IF_DEBUGGING("test"); // -> print("test");
#define DEBUG
PRINT_IF_DEBUGGING("test"); // -> debugPrint("test");
#undef DEBUG
PRINT_IF_DEBUGGING("test"); // -> print("test");
3. Caveats
One small caveat with this is that if DEBUG is defined it must expand to a valid preprocessing token (so it must only contain letters, digits and underscores) - otherwise the concatenation will result in an error.
So this would not work:
#define DEBUG ()
#define DEBUG +
In my project I have very many files and I want to manage debug with C++ macros. For every file, I want to use its own switch for enable or disable debug and adjust debug level. So basically there is shared file with settings:
This is how shared file debug.h looks:
#define DEBUG_LEVEL_LOG -1
#define DEBUG_LEVEL_NONE 0
#define DEBUG_LEVEL_ERROR 1
#define DEBUG_LEVEL_WARNING 2
#define DEBUG_LEVEL_INFO 3
#define DEBUG_LEVEL_DEBUG 4
#define DEBUG_LEVEL_TRACE 5
#ifndef ON
#define ON 1
#endif
#ifndef OFF
#define OFF 0
#endif
// setings for component "wireless"
#define WIRELESS_DEBUGGING ON
#define WIRELESS_DEBUGGING_LEVEL DEBUG_LEVEL_ERROR
// settings for another components
...
In every file I want to debug with this settings I need to define another bunch of macros. For example file "wireless.h"
#ifndef WIRELESS_DEBUGGING
#define WIRELESS_DEBUGGING_LEVEL DEBUG_LEVEL_NONE
#endif
#if WIRELESS_DEBUGGING
#if WIRELESS_DEBUGGING_LEVEL >= DEBUG_LEVEL_LOG
#define WIRELESS_LOG(...); Logger::log(__VA_ARGS__);
#else
#define WIRELESS_LOG(...); {}
#endif
#if WIRELESS_DEBUGGING_LEVEL >= DEBUG_LEVEL_ERROR
#define WIRELESS_ERROR(...); Logger::error(__VA_ARGS__);
#else
#define WIRELESS_ERROR(...); {}
#endif
#if WIRELESS_DEBUGGING_LEVEL >= DEBUG_LEVEL_WARNING
#define WIRELESS_WARNING(...); Logger::warning(__VA_ARGS__);
#else
#define WIRELESS_WARNING(...); {}
#endif
#if WIRELESS_DEBUGGING_LEVEL >= DEBUG_LEVEL_INFO
#define WIRELESS_INFO(...); Logger::info(__VA_ARGS__);
#else
#define WIRELESS_INFO(...); {}
#endif
#if WIRELESS_DEBUGGING_LEVEL >= DEBUG_LEVEL_DEBUG
#define WIRELESS_DEBUG(...); Logger::debug(__VA_ARGS__);
#else
#define WIRELESS_DEBUG(...); {}
#endif
#if WIRELESS_DEBUGGING_LEVEL >= DEBUG_LEVEL_TRACE
#define WIRELESS_TRACE(...); Logger::trace(__VA_ARGS__);
#else
#define WIRELESS_TRACE(...); {}
#endif
#else
#define WIRELESS_LOG(...); {}
#define WIRELESS_ERROR(...); {}
#define WIRELESS_WARNING(...); {}
#define WIRELESS_INFO(...); {}
#define WIRELESS_DEBUG(...); {}
#define WIRELESS_TRACE(...); {}
#endif
When I want to debug given component, I simply use something like this (in wireless.cpp)
WIRELESS_TRACE("wireless: hello world\n");
... etc ...
So far it's working. And here is the question: I don't want to use "local" bunch of definitions similar to definitions in file "wireless.h" in every component I'm using only with different prefix. Instead of this I want to have some "super macro" which will look similar to this
REGISTER_DEBUG(WIRELESS);
Is there a way how to achieve this using some concatenation and multi-line macro? I have found that using #define inside #define is forbidden.
I'm not completely sure what you want, so if this doesn't fit let me know and I'll delete.
There is the possibility of concatenating tokens in the preprocessor using ##. See, for example, https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html
This is somewhat clumsy, but should do the trick:
#define DEBUG_LEVEL_LOG -1
#define DEBUG_LEVEL_NONE 0
#define DEBUG_LEVEL_ERROR 1
#define DEBUG_LEVEL_WARNING 2
#define DEBUG_LEVEL_INFO 3
#define DEBUG_LEVEL_DEBUG 4
#define DEBUG_LEVEL_TRACE 5
#define TRACE(a,...) _TRACE(a,__VA_ARGS__)
#define _TRACE(a,...) __TRACE_##a(__VA_ARGS__)
#define __TRACE_5(...) do{Logger::trace(__VA_ARGS__);}while(0)
Here is the clumsiness: you also need to define __TRACE_4, __TRACE_3 and so on to be empty. And then you need to define the same thing for Debug:
#define __DEBUG_4(...) do{Logger::debug(__VA_ARGS__);}while(0)
But in the end, after you defined your Wireless log level:
#define WIRELESS_LEVEL 5
you can just call the macro just like this:
TRACE(WIRELESS_LEVEL,"wireless: hello world\n");
Edit
Alternatively (this might be cleaner):
#define __PRINT_55(...) do{Logger::trace(__VA_ARGS__);}while(0)
#define __PRINT_44(...) do{Logger::debug(__VA_ARGS__);}while(0)
// etc...
// Also need to define what you need to be not printed:
#define __PRINT_01(...)
// etc...
#define PRINT(a,b,...) _PRINT(a,b,__VA_ARGS__)
#define _PRINT(a,b,...) __PRINT_##a##b(__VA_ARGS__)
Now you can call your function like this:
PRINT(DEBUG_LEVEL_TRACE, WIRELESS_LEVEL, "Hello world\n");
You can get there by switching from macros to inline functions. Something like this:
// debug.h
enum DebugLevel {
DEBUG_LEVEL_LOG = -1,
DEBUG_LEVEL_NONE = 0,
DEBUG_LEVEL_ERROR = 1,
DEBUG_LEVEL_WARNING = 2,
DEBUG_LEVEL_INFO = 3,
DEBUG_LEVEL_DEBUG = 4,
DEBUG_LEVEL_TRACE = 5
};
// settings for component "wireless"
constexpr bool WIRELESS_DEBUGGING = true;
constexpr DebugLevel WIRELESS_DEBUGGING_LEVEL = DEBUG_LEVEL_ERROR;
#define REGISTER_DEBUG_FUNC(topic, level, func) \
template <typename... Args> \
inline void topic##_##level(Args&& ... args) { \
if ( topic##_DEBUGGING && topic##_DEBUGGING_LEVEL >= DEBUG_LEVEL_##level ) \
Logger::func(std::forward<Args>(args)...); \
}
#define REGISTER_DEBUG(topic) \
REGISTER_DEBUG_FUNC(topic, LOG, log) \
REGISTER_DEBUG_FUNC(topic, ERROR, error) \
REGISTER_DEBUG_FUNC(topic, WARNING, warning) \
REGISTER_DEBUG_FUNC(topic, INFO, info) \
REGISTER_DEBUG_FUNC(topic, DEBUG, debug) \
REGISTER_DEBUG_FUNC(topic, TRACE, trace)
// wireless.h
REGISTER_DEBUG(WIRELESS)
I want to know if we can have recursive macros in C/C++? If yes, please provide a sample example.
Second thing: why am I not able to execute the below code? What is the mistake I am doing? Is it because of recursive macros?
# define pr(n) ((n==1)? 1 : pr(n-1))
void main ()
{
int a=5;
cout<<"result: "<< pr(5) <<endl;
getch();
}
Macros don't directly expand recursively, but there are workarounds. When the preprocessor scans and expands pr(5):
pr(5)
^
it creates a disabling context, so that when it sees pr again:
((5==1)? 1 : pr(5-1))
^
it becomes painted blue, and can no longer expand, no matter what we try. But we can prevent our macro from becoming painted blue by using deferred expressions and some indirection:
# define EMPTY(...)
# define DEFER(...) __VA_ARGS__ EMPTY()
# define OBSTRUCT(...) __VA_ARGS__ DEFER(EMPTY)()
# define EXPAND(...) __VA_ARGS__
# define pr_id() pr
# define pr(n) ((n==1)? 1 : DEFER(pr_id)()(n-1))
So now it will expand like this:
pr(5) // Expands to ((5==1)? 1 : pr_id ()(5 -1))
Which is perfect, because pr was never painted blue. We just need to apply another scan to make it expand further:
EXPAND(pr(5)) // Expands to ((5==1)? 1 : ((5 -1==1)? 1 : pr_id ()(5 -1 -1)))
We can apply two scans to make it expand further:
EXPAND(EXPAND(pr(5))) // Expands to ((5==1)? 1 : ((5 -1==1)? 1 : ((5 -1 -1==1)? 1 : pr_id ()(5 -1 -1 -1))))
However, since there is no termination condition, we can never apply enough scans. I'm not sure what you want to accomplish, but if you are curious on how to create recursive macros, here is an example of how to create a recursive repeat macro.
First a macro to apply a lot of scans:
#define EVAL(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
#define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
#define EVAL2(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
#define EVAL3(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__)))
#define EVAL4(...) EVAL5(EVAL5(EVAL5(__VA_ARGS__)))
#define EVAL5(...) __VA_ARGS__
Next, a concat macro which is useful for pattern matching:
#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__)
#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__
Increment and decrement counters:
#define INC(x) PRIMITIVE_CAT(INC_, x)
#define INC_0 1
#define INC_1 2
#define INC_2 3
#define INC_3 4
#define INC_4 5
#define INC_5 6
#define INC_6 7
#define INC_7 8
#define INC_8 9
#define INC_9 9
#define DEC(x) PRIMITIVE_CAT(DEC_, x)
#define DEC_0 0
#define DEC_1 0
#define DEC_2 1
#define DEC_3 2
#define DEC_4 3
#define DEC_5 4
#define DEC_6 5
#define DEC_7 6
#define DEC_8 7
#define DEC_9 8
Some macros useful for conditionals:
#define CHECK_N(x, n, ...) n
#define CHECK(...) CHECK_N(__VA_ARGS__, 0,)
#define NOT(x) CHECK(PRIMITIVE_CAT(NOT_, x))
#define NOT_0 ~, 1,
#define COMPL(b) PRIMITIVE_CAT(COMPL_, b)
#define COMPL_0 1
#define COMPL_1 0
#define BOOL(x) COMPL(NOT(x))
#define IIF(c) PRIMITIVE_CAT(IIF_, c)
#define IIF_0(t, ...) __VA_ARGS__
#define IIF_1(t, ...) t
#define IF(c) IIF(BOOL(c))
#define EAT(...)
#define EXPAND(...) __VA_ARGS__
#define WHEN(c) IF(c)(EXPAND, EAT)
Putting it all together we can create a repeat macro:
#define REPEAT(count, macro, ...) \
WHEN(count) \
( \
OBSTRUCT(REPEAT_INDIRECT) () \
( \
DEC(count), macro, __VA_ARGS__ \
) \
OBSTRUCT(macro) \
( \
DEC(count), __VA_ARGS__ \
) \
)
#define REPEAT_INDIRECT() REPEAT
//An example of using this macro
#define M(i, _) i
EVAL(REPEAT(8, M, ~)) // 0 1 2 3 4 5 6 7
So, yes with some workarounds you can have recursive macros in C/C++.
Your compiler probably provides an option to only pre-process, not actually compile. This is useful if you are trying to find a problem in a macro. For example using g++ -E:
> g++ -E recursiveMacro.c
# 1 "recursiveMacro.c"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "recursiveMacro.c"
void main ()
{
int a=5;
cout<<"result: "<< ((5==1)? 1 : pr(5 -1)) <<endl;
getch();
}
As you can see, it is not recursive. pr(x) is only replaced once during pre-processing. The important thing to remember is that all the pre-processor does is blindly replace one text string with another, it doesn't actually evaluate expressions like (x == 1).
The reason your code will not compile is that pr(5 -1) was not replaced by the pre-processor, so it ends up in the source as a call to an undefined function.
You're not supposed to have recursive macros in C or C++.
The relevant language from the C++ standard, section 16.3.4 paragraph 2:
If the name of the macro being replaced is found during this scan of the replacement list (not including the rest of the source file’s preprocessing tokens), it is not replaced. Furthermore, if any nested replacements encounter the name of the macro being replaced, it is not replaced. These nonreplaced macro name preprocessing tokens are no longer available for further replacement even if they are later (re)examined in contexts in which that macro name preprocessing token would otherwise have been replaced.
There's some wiggle room in this language. With multiple macros that invoke one another, there's a grey area where that wording doesn't quite say what should be done. There is an active issue against the C++ standard regarding this language lawyer problem; see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#268 .
Ignoring that language lawyer issue, every compiler vendor understands the intent:
Recursive macros are not allowed in C or in C++.
Most likely you are not able to execute it because you can't compile it. Also if it would compile correctly, it would always return 1. Did you mean (n==1)? 1 : n * pr(n-1).
Macros can't be recursive. According to chapter 16.3.4.2 (thanks Loki Astari), if the current macro is found in the replacement list, it is left as is, thus your pr in the definition will not be changed:
If the name of the macro being replaced is found during this scan of
the replacement list (not including the rest of the source file's pre-
processing tokens), it is not replaced. Further, if any nested
replacements encounter the name of the macro being replaced, it is not
replaced. These nonreplaced macro name preprocessing tokens are no
longer available for further replacement even if they are later
(re)examined in contexts in which that macro name preprocessing token
would otherwise have been replaced.
Your call:
cout<<"result: "<< pr(5) <<endl;
was converted by preprocessor into:
cout<<"result: "<< (5==1)? 1 : pr(5-1) <<endl;
During this, the definition of pr macro is 'lost', and compiler shows an error like "‘pr’ was not declared in this scope (fact)" because there is no function named pr.
Use of macros is not encouraged in C++. Why don't you just write a function?
In this case you could even write a template function so it will be resolved in compile time, and will behave as a constant value:
template <int n>
int pr() { pr<n-1>(); }
template <>
int pr<1>() { return 1; }
TLDR.
True recursion itself is easy done by duplicating macros in two names, with each referencing other. But usefulness of this feature is doubtful, because this requires nested conditional macro to make recursion finite. All conditional macro-operators are essentially multiline, because #else and #endif lines must be separate lines (serious cpp limitation), which means, that conditional macro-definitions are impossible by design (thus, recusion itself would be useless).
You can't have recursive macros in C or C++.
I know C++ template metaprogramming is Turing-complete. Does the same thing hold for preprocessor metaprogramming?
Well macros don't directly expand recursively, but there are ways we can work around this.
The easiest way of doing recursion in the preprocessor is to use a deferred expression. A deferred expression is an expression that requires more scans to fully expand:
#define EMPTY()
#define DEFER(id) id EMPTY()
#define OBSTRUCT(...) __VA_ARGS__ DEFER(EMPTY)()
#define EXPAND(...) __VA_ARGS__
#define A() 123
A() // Expands to 123
DEFER(A)() // Expands to A () because it requires one more scan to fully expand
EXPAND(DEFER(A)()) // Expands to 123, because the EXPAND macro forces another scan
Why is this important? Well when a macro is scanned and expanding, it creates a disabling context. This disabling context will cause a token, that refers to the currently expanding macro, to be painted blue. Thus, once its painted blue, the macro will no longer expand. This is why macros don't expand recursively. However, a disabling context only exists during one scan, so by deferring an expansion we can prevent our macros from becoming painted blue. We will just need to apply more scans to the expression. We can do that using this EVAL macro:
#define EVAL(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
#define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
#define EVAL2(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
#define EVAL3(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__)))
#define EVAL4(...) EVAL5(EVAL5(EVAL5(__VA_ARGS__)))
#define EVAL5(...) __VA_ARGS__
Now if we want to implement a REPEAT macro using recursion, first we need some increment and decrement operators to handle state:
#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__)
#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__
#define INC(x) PRIMITIVE_CAT(INC_, x)
#define INC_0 1
#define INC_1 2
#define INC_2 3
#define INC_3 4
#define INC_4 5
#define INC_5 6
#define INC_6 7
#define INC_7 8
#define INC_8 9
#define INC_9 9
#define DEC(x) PRIMITIVE_CAT(DEC_, x)
#define DEC_0 0
#define DEC_1 0
#define DEC_2 1
#define DEC_3 2
#define DEC_4 3
#define DEC_5 4
#define DEC_6 5
#define DEC_7 6
#define DEC_8 7
#define DEC_9 8
Next we need a few more macros to do logic:
#define CHECK_N(x, n, ...) n
#define CHECK(...) CHECK_N(__VA_ARGS__, 0,)
#define NOT(x) CHECK(PRIMITIVE_CAT(NOT_, x))
#define NOT_0 ~, 1,
#define COMPL(b) PRIMITIVE_CAT(COMPL_, b)
#define COMPL_0 1
#define COMPL_1 0
#define BOOL(x) COMPL(NOT(x))
#define IIF(c) PRIMITIVE_CAT(IIF_, c)
#define IIF_0(t, ...) __VA_ARGS__
#define IIF_1(t, ...) t
#define IF(c) IIF(BOOL(c))
#define EAT(...)
#define EXPAND(...) __VA_ARGS__
#define WHEN(c) IF(c)(EXPAND, EAT)
Now with all these macros we can write a recursive REPEAT macro. We use a REPEAT_INDIRECT macro to refer back to itself recursively. This prevents the macro from being painted blue, since it will expand on a different scan(and using a different disabling context). We use OBSTRUCT here, which will defer the expansion twice. This is necessary because the conditional WHEN applies one scan already.
#define REPEAT(count, macro, ...) \
WHEN(count) \
( \
OBSTRUCT(REPEAT_INDIRECT) () \
( \
DEC(count), macro, __VA_ARGS__ \
) \
OBSTRUCT(macro) \
( \
DEC(count), __VA_ARGS__ \
) \
)
#define REPEAT_INDIRECT() REPEAT
//An example of using this macro
#define M(i, _) i
EVAL(REPEAT(8, M, ~)) // 0 1 2 3 4 5 6 7
Now this example is limited to 10 repeats, because of limitations of the counter. Just like a repeat counter in a computer would be limited by the finite memory. Multiple repeat counters could be combined together to workaround this limitation, just like in a computer. Furthermore, we could define a FOREVER macro:
#define FOREVER() \
? \
DEFER(FOREVER_INDIRECT) () ()
#define FOREVER_INDIRECT() FOREVER
// Outputs question marks forever
EVAL(FOREVER())
This will try to output ? forever, but will eventually stop because there are no more scans being applied. Now the question is, if we gave it an infinite number of scans would this algorithm complete? This is known as the halting problem, and Turing completeness is necessary to prove the undecidability of the halting problem. So as you can see, the preprocessor can act as a Turing complete language, but instead of being limited to the finite memory of a computer it is instead limited by the finite number of scans applied.
No. The C++ preprocessor does not allow for unlimited state. You only have a finite number of on/off states, plus a include stack. This makes it a push-down automaton, not a turing machine (this ignores also the fact that preprocessor recursion is limited - but so is template recursion).
However, if you bend your definitions a bit, this is possible by invoking the preprocessor multiple times - by allowing the preprocessor to generate a program which re-invokes the preprocessor, and looping externally, it is indeed possible to make a turing machine with the preprocessor. The linked example uses C, but it should be adaptable into C++ easily enough.
Can somebody explain the following code please?
#if 1
// loop type
#define FOR_IS_FASTER 1
#define WHILE_IS_FASTER 0
// indexing type
#define PREINCREMENT_IS_FASTER 1
#define POSTINCREMENT_IS_FASTER 0
#else
// loop type
#define FOR_IS_FASTER 1
#define WHILE_IS_FASTER 0
// indexing type
#define PREINCREMENT_IS_FASTER 0
#define POSTINCREMENT_IS_FASTER 1
#endif
#if PREINCREMENT_IS_FASTER
#define ZXP(z) (*++(z))
#define ZX(z) (*(z))
#define PZ(z) (++(z))
#define ZP(z) (z)
#define ZOFF (1)
#elif POSTINCREMENT_IS_FASTER
#define ZXP(z) (*(z)++)
#define ZX(z) (*(z))
#define PZ(z) (z)
#define ZP(z) ((z)++)
#define ZOFF (0)
#endif
I can understand what the functions are doing but for example
how does the pre-processor choose which ZXP will be execute if we call it later?
What do the 1 and 0 stand for?
The #if 1 triggers the first group of #defines, which set PREINCREMENT_IS_FASTER to 1. Because of this, #if PREINCREMENT_IS_FASTER triggers the first #define ZXP....
There is nothing exceptional about 1 and 0 in this context. The #if preprocessor directive succeeds if its argument is non-zero.
You can switch to the alternate form by changing the #if 1 at the top of the file with #if 0. (Thank you #rabidmachine for the tip.)
I'm probably inclined to agree with UncleBens and suggest that it's done so that you don't understand it, because the whole lot is totally useless.