0

Could you explain to me what is actually happening in my app? The outcome of my program is "0 1 1" when I expect "0 1 2" and so on...

#include <iostream>

template<int N>
struct counter {
    friend constexpr int get(counter<N>);
};

template<int N>
struct writer {
    friend constexpr int get(counter<N>) {
        return N;
    }
};

template<int N, bool B = noexcept(get(counter<N + 1>()))>
struct GetMaxCounter
{
    static constexpr int max = GetMaxCounter<N + 1>::max;
};

template<int N>
struct GetMaxCounter<N, false>
{
    static constexpr int max = N;
};

int main()
{
    std::cout << GetMaxCounter<0>::max << std::endl;
    writer<1>();
    std::cout << GetMaxCounter<0>::max << std::endl;
    writer<2>();
    std::cout << GetMaxCounter<0>::max << std::endl;
}

What happens when I call GetMaxCounter<0>::max for the third time? Shouldn't template argument B be reevaluated to "true"?

Kamisama
  • 63
  • 8
  • 1
    [I've been there too.](https://stackoverflow.com/questions/51601439/constexpr-counter-that-works-on-gcc-8-and-is-not-restricted-to-namespace-scope) I was told that stateful template metaprogramming was abolished in C++17 due to [`[temp.res]/8.5`](http://eel.is/c++draft/temp.res#8.5) (the linked question calls it `8.4`, the numeration was changed since then), which allegedly makes the code ill-formed, NDR. But I concede I'm not sure how exactly that section applied here. – HolyBlackCat Jan 13 '19 at 23:55
  • 1
    I don't even know what `get` in the 3rd paragraph is referring to. I want to share this though: http://boostorg.github.io/hana/index.html#tutorial-integral – matiu Jan 14 '19 at 00:09

1 Answers1

0

Kind of a late answer, but the problem is due to the fact that you only have two "versions" of the class GetMaxCounter<N> i.e. GetMaxCounter<N, false> and GetMaxCounter<N, true>.

Essentially the max member is fixed to GetMaxCounter<0,false>::max (== 0) on the first call to GetMaxCounter<0>::max, when writer<1> is called, GetMaxCounter<0,true>::max is defined to be GetMaxCounter<1, false>::max (== 1).

Regardless of whether you called writer<2> or not, any subsequent GetMaxCounter<0> will be evaluated as GetMaxCounter<0, true> which has GetMaxCounter<0, true>::max previously defined as GetMaxCounter<1, false>::max and will not change.

bryan2402
  • 1
  • 1
  • 1