Why does removing the default parameter break this constexpr counter?

Viewed 406

Consider the following code that implements a compile time counter.

#include <iostream>

template<int>
struct Flag { friend constexpr int flag(Flag); };

template<int N>
struct Writer
{
    friend constexpr int flag(Flag<N>) { return 0; }
};

template<int N>
constexpr int reader(float, Flag<N>) { return N; }

template<int N, int = flag(Flag<N>{})>
constexpr int reader(int, Flag<N>, int value = reader(0, Flag<N + 1>{}))
{
    return value;
}

template<int N = reader(0, Flag<0>{}), int = sizeof(Writer<N>) >
constexpr int next() { return N; }


int main() {
    constexpr int a = next();
    constexpr int b = next();
    constexpr int c = next();
    constexpr int d = next();
    std::cout << a << b << c << d << '\n'; // 0123
}

For the second reader overload, if I put the default parameter inside the body of the function, like so:

template<int N, int = flag(Flag<N>{})>
constexpr int reader(int, Flag<N>)
{
    return reader(0, Flag<N + 1>{});
}

Then the output will become:

0111

Why does this happen? What makes the second version not work anymore?

If it matters, I'm using Visual Studio 2015.2.

2 Answers
Related