问题
I'm currently using the __COUNTER__
macro in my C library code to generate unique integer identifiers. It works nicely, but I see two issues:
- It's not part of any C or C++ standard.
- Independent code that also uses
__COUNTER__
might get confused.
I thus wish to implement an equivalent to __COUNTER__
myself.
Alternatives that I'm aware of, but do not want to use:
__LINE__
(because multiple macros per line wouldn't get unique ids)BOOST_PP_COUNTER
(because I don't want aboost
dependency)
BOOST_PP_COUNTER
proves that this can be done, even though other answers claim it is impossible.
In essence, I'm looking for a header file "mycounter.h", such that
#include "mycounter.h"
__MYCOUNTER__
__MYCOUNTER__ __MYCOUNTER__
__MYCOUNTER__
will be preprocessed by gcc -E
to
(...)
0
1 2
3
without using the built-in __COUNTER__
.
Note: Earlier, this question was marked as a duplicate of this, which deals with using __COUNTER__
rather than avoiding it.
回答1:
You can't implement __COUNTER__
directly. The preprocessor is purely functional - no state changes. A hidden counter is inherently impossible in such a system. (BOOST_PP_COUNTER
does not prove what you want can be done - it relies on #include
and is therefore one-per-line only - may as well use __LINE__
. That said, the implementation is brilliant, you should read it anyway.)
What you can do is refactor your metaprogram so that the counter could be applied to the input data by a pure function. e.g. using good ol' Order:
#include <order/interpreter.h>
#define ORDER_PP_DEF_8map_count \
ORDER_PP_FN(8fn(8L, 8rec_mc(8L, 8nil, 0)))
#define ORDER_PP_DEF_8rec_mc \
ORDER_PP_FN(8fn(8L, 8R, 8C, \
8if(8is_nil(8L), \
8R, \
8let((8H, 8seq_head(8L)) \
(8T, 8seq_tail(8L)) \
(8D, 8plus(8C, 1)), \
8if(8is_seq(8H), \
8rec_mc(8T, 8seq_append(8R, 8seq_take(1, 8L)), 8C), \
8rec_mc(8T, 8seq_append(8R, 8seq(8C)), 8D) )))))
ORDER_PP (
8map_count(8seq( 8seq(8(A)), 8true, 8seq(8(C)), 8true, 8true )) //((A))(0)((C))(1)(2)
)
(recurses down the list, leaving sublist elements where they are and replacing non-list elements - represented by 8false
- with an incrementing counter variable)
I assume you don't actually want to simply drop __COUNTER__
values at the program toplevel, so if you can place the code into which you need to weave __COUNTER__
values inside a wrapper macro that splits it into some kind of sequence or list, you can then feed the list to a pure function similar to the example.
Of course a metaprogramming library capable of expressing such code is going to be significantly less portable and maintainable than __COUNTER__
anyway. __COUNTER__
is supported by Intel, GCC, Clang and MSVC. (not everyone, e.g. pcc
doesn't have it, but does anyone even use that?) Arguably if you demonstrate the feature in use in real code, it makes a stronger case to the standardisation committee that __COUNTER__
should become part of the next C standard.
回答2:
You are confusing two different things:
1 - the preprocessor which handles#define
and #include
like stuff. It does only works as the text (meaning character sequences) level and has very few computing capabilities. It is so limited that it cannot implement __COUNTER__
. The preprocessor work consist only in macro expansion and file replacement. The crucial point it that it occur before the compilation even start.
2 - the C++ language and in particular the template (meta)programming language which can be used to compute stuff during the compilation phase. It is indeed turing complete but as I already said compilation start after preprocessing.
So what you are asking is not doable in standard C or C++. To solve this problem boost
implement its own preprocessor which is not standard compliant and has much more computing capabilities. In particular it is possible to use build an analogue to __counter__
with it.
回答3:
This small header of mine contains an own implementation of a C preprocessor counter (it uses a slightly different syntax).
来源:https://stackoverflow.com/questions/22693565/c-preprocessor-own-implementation-for-counter