The __COUNTER__
symbol is provided by VC++ and GCC, and gives an increasing non-negative integral value each time it is used.
I\'m interested to learn w
I've never used it for anything but a DEBUG macro. It's convenient to be able to say
#define WAYPOINT \
do { if(dbg) printf("At marker: %d\n", __COUNTER__); } while(0);
I've used it in a compile-time assertion macro to have the macro create a name for a typedef that will be unique. See
if you want the gory details.
It's used in ClickHouse's metrics system.
namespace CurrentMetrics
{
#define M(NAME) extern const Metric NAME = __COUNTER__;
APPLY_FOR_METRICS(M)
#undef M
constexpr Metric END = __COUNTER__;
std::atomic<Value> values[END] {}; /// Global variable, initialized by zeros.
const char * getDescription(Metric event)
{
static const char * descriptions[] =
{
#define M(NAME) #NAME,
APPLY_FOR_METRICS(M)
#undef M
};
return descriptions[event];
}
Metric end() { return END; }
}
__COUNTER__
is useful anywhere you need a unique name. I have used it extensively for RAII style locks and stacks. Consider:
struct TLock
{
void Lock();
void Unlock();
}
g_Lock1, g_Lock2;
struct TLockUse
{
TLockUse( TLock &lock ):m_Lock(lock){ m_Lock.Lock(); }
~TLockUse(){ m_Lock.Unlock(); }
TLock &m_Lock;
};
void DoSomething()
{
TLockUse lock_use1( g_Lock1 );
TLockUse lock_use2( g_Lock2 );
// ...
}
It gets tedious to name the lock uses, and can even become a source of errors if they're not all declared at the top of a block. How do you know if you're on lock_use4
or lock_use11
? It's also needless pollution of the namespace - I never need to refer to the lock use objects by name. So I use __COUNTER__
:
#define CONCAT_IMPL( x, y ) x##y
#define MACRO_CONCAT( x, y ) CONCAT_IMPL( x, y )
#define USE_LOCK( lock ) TLockUse MACRO_CONCAT( LockUse, __COUNTER__ )( lock )
void DoSomething2()
{
USE_LOCK( g_Lock1 );
USE_LOCK( g_Lock2 );
// ...
}
But don't get hung up on the fact I called the objects locks - any function(s) that need to get called in matching pairs fit this pattern. You might even have multiple uses on the same "lock" in a given block.
It's used in the xCover code coverage library, to mark the lines that execution passes through, to find ones that are not covered.
I'm interested to learn whether anyone's ever used it,
Yes, but as you can see from many examples in this Q&A, __LINE__
, which is standardized, would also be sufficient in most cases.
__COUNTER__
is only really necessary in cases where the count must increase by one each time, or it must have continuity over several #include
files.
and whether it's something that would be worth standardising?
__COUNTER__
, unlike __LINE__
, is very dangerous because it depends on which header files are included and what order. If two .cpp
files (translation units) include a header file that use __COUNTER__
, but the header file obtains different count sequences in the different instances, they may use different definitions of the same thing and violate the one-definition rule.
One-definition rule violations are very difficult to catch and potentially create bugs and security risks. The few use-cases of __COUNTER__
don't really outweigh the downside and lack of scalability.
Even if you never ship code that uses __COUNTER__
, it can be useful when prototyping an enumeration sequence, saving you the trouble of assigning names before the membership is concrete.