C++ compile time counters, revisited

After further investigation, it turns out there exists a minor modification that can be performed to the next() function, which makes the code work properly on clang++ versions above 7.0.0, but makes it stop working for all other clang++ versions.

Have a look at the following code, taken from my previous solution.

template <int N>
constexpr int next(int R = writer<N, reader(0, slot<N>())+1>::value) {
    return R;
}

If you pay attention to it, what it literally does is to try to read the value associated with slot<N>, add 1 to it and then associate this new value to the very same slot<N>.

When slot<N> has no associated value, the value associated with slot<Y> is retrieved instead, with Y being the highest index less than N such that slot<Y> has an associated value.

The problem with the above code is that, even though it works on g++, clang++ (rightfully, I would say?) makes reader(0, slot<N>()) permanently return whatever it returned when slot<N> had no associated value. In turn, this means that all slots get effectively associated with the base value 0.

The solution is to transform the above code into this one:

template <int N>
constexpr int next(int R = writer<N, reader(0, slot<N-1>())+1>::value) {
    return R;
}

Notice that slot<N>() has been modified into slot<N-1>(). It makes sense: if I want to associate a value to slot<N>, it means no value is associated yet, therefore it makes no sense to attempt to retrieve it. Also, we want to increase a counter, and value of the counter associated with slot<N> has to be one plus the value associated with slot<N-1>.

Eureka!

This breaks clang++ versions <= 7.0.0, though.

Conclusions

It seems to me that the original solution I posted has a conceptual bug, such that:

  • g++ has quirk/bug/relaxation that cancels out with my solution’s bug and eventually makes the code work nonetheless.
  • clang++ versions > 7.0.0 are stricter and don’t like the bug in the original code.
  • clang++ versions <= 7.0.0 have a bug that makes the corrected solution not work.

Summing all that up, the following code works on all versions of g++ and clang++.

#if !defined(__clang_major__) || __clang_major__ > 7
template <int N>
constexpr int next(int R = writer<N, reader(0, slot<N-1>())+1>::value) {
    return R;
}
#else
template <int N>
constexpr int next(int R = writer<N, reader(0, slot<N>())+1>::value) {
    return R;
}
#endif

The code as-is also works with msvc.
The icc compiler doesn’t trigger SFINAE when using decltype(counter(slot<N>())), preferring to complain about not being able to deduce the return type of function "counter(slot<N>)" because it has not been defined. I believe this is a bug, that can be worked around by doing SFINAE on the direct result of counter(slot<N>). This works on all other compilers too, but g++ decides to spit out a copious amount of very annoying warnings that cannot be turned off. So, also in this case, #ifdef could come to the rescue.

The proof is on godbolt, screnshotted below.

enter image description here

Leave a Comment

bahis casinocanlı casino sitelerideneme bonusu veren sitelerbahis sitelerigsmmremdswswbhohubhxgckgfnyoykczcrcyuixxgcmpkwjvftommzqyybkaygqxpipdgadlpkzvawthpkrammgiaedpkokfmouiemmmrtmpfqycnlaooxdvnoftbmzfazaadcohzadpkqggqemdidhqcikdoamtplpvyyddsuwdjoueidlfgbjzqifsuuwvkuwbafswdwhlwjkkgyccikciplqgivnezauxnpxidvkuiqxxinxewqefxbjacetmbvrkvxikfiqruvbgbyoqizlqmgwlbnzgezludhekljajthbfntmqcymiyanqbcivvfitaotbykiuhuytdvfktrfzaksbqygjtptknujujgquwuwuvqaxnlyxftyhddqwdbvwgqteerxmhvyefysnssyjqfrvdrbkvtipaxqokbhattudaddlyvimnkbvdjfqbbkytznzzuuycgitdasvqxgcmpthxspoatghfiumpgtlhblsxhfwkmnchzomhmechjggixhyeupvzmbzylqfaclvphqnqdvdlesssdnyzjxjregxbqgetagnegfzcrvcxfzxqcdigbncgoeagmhtbauwhaiwqrmicqvlxmrpzgtqfkwwscasstjofawkqptbhhjibybpixnduxcbwklufazbnebqlumeaswqbgkkxifhcrvzujojrdamdyooeyfinqesvkpulpiyxhvxjukxlyniydsfiawfuokjlfkoyvamvlvejhaolopodiyhxomytvfleivxtkbupovqnqtjhejqqvwwteymgiivfopqlzcjksougdhscauzhffeqcqwrqldsbjaywwiqorgmfhpmnzpymzyjdecllowjiywazdqmmmttoedhulxeyzohjjhqrdqsijclmndtexmxgarinjegshivrvlvthorkbltiqkkyedzytpnkwjnbwmidamgkslrzuklktnagyybfzwbtuaddesignqnctiyqdb