I have a compile-time counter that I used for years, inspired by these answers. It works in C++03/11, and as far as I tested, relatively well on major compilers:
namespace meta
{
template<unsigned int n> struct Count { char data[n]; };
template<int n> struct ICount : public ICount<n-1> {};
template<> struct ICount<0> {};
#define MAX_COUNT 64
#define MAKE_COUNTER( _tag_ ) \
static ::meta::Count<1> _counter ## _tag_ (::meta::ICount<1>)
#define GET_COUNT( _tag_ ) \
(sizeof(_counter ## _tag_ (::meta::ICount<MAX_COUNT + 1>())) - 1)
#define INC_COUNT( _tag_ ) \
static ::meta::Count<GET_COUNT(_tag_) + 2> _counter ## _tag_ (::meta::ICount<2 + GET_COUNT(_tag_)>)
}
The following test compiles and runs perfectly (expected output is 0 1 2 3
):
struct Test
{
MAKE_COUNTER( uu );
static const unsigned int a = GET_COUNT( uu );
INC_COUNT( uu );
static const unsigned int b = GET_COUNT( uu );
INC_COUNT( uu );
static const unsigned int c = GET_COUNT( uu );
INC_COUNT( uu );
static const unsigned int d = GET_COUNT( uu );
};
template<typename T>
void test()
{
std::cout << T::a << " " << T::b << " " << T::c << " " << T::d << "\n";
}
int main()
{
test<Test>();
}
However, I found a case were I see a very strange behavior happening with clang and gcc. If you change Test
to be a template struct, taking an int for example (template<int> struct Test
, and test<Test<42> >()
in main
), clang and gcc both fail to compile, complaining that I am redefining the counter function (while msvc compiles it without problems). For some reason the compiler fails to compute a sizeof in a template class.
clang find the error at the third INC_COUNT
, while gcc find it at the second one.
I manually expanded this macro, and:
for clang, it gives
static ::meta::Count<GET_COUNT(uu)+2> _counteruu(::meta::ICount<(sizeof(_counteruu(::meta::ICount<65>())) - 1)+2>); // ^ ^
removing the underlined parentheses solves the issue.
for gcc: moving the
+2
before thesizeof
is the only work-around
The sad note is that these workarounds seem not to work when included in the macros. It's like the compiler just forgets how to compute the result of sizeof after some time...
Why is this happening ? Am I doing something wrong, or is it just compiler bugs (since clang and gcc don't even report the same line) ?
Note: I know there is a gcc bug about this counter. The question is not about this bug.