Является ли состояние метапрограммирования неупорядоченным (пока)?

Одно из моих самых любимых/злых изобретений, с которыми я столкнулся, - это счетчик constexpr, также известный как метапрограммирование. Как упоминалось в сообщении, это кажется законным в С++ 14, и мне интересно, что-то изменилось с С++ 17?

Ниже приведена реализация, основанная на публикации post

template <int N>
struct flag
{
    friend constexpr int adl_flag(flag<N>);
    constexpr operator int() { return N; }
};

template <int N>
struct write
{
    friend constexpr int adl_flag(flag<N>) { return N; }
    static constexpr int value = N;
};

template <int N, int = adl_flag(flag<N>{})>
constexpr int read(int, flag<N>, int R = read(0, flag<N + 1>{}))
{
    return R;
}

template <int N>
constexpr int read(float, flag<N>)
{
    return N;
}

template <int N = 0>
constexpr int counter(int R = write<read(0, flag<0>{}) + N>::value)
{
    return R;
}

И мы используем его как

static_assert(counter() != counter(), "Your compiler is mad at you"); 

template<int = counter()>
struct S {};

static_assert(!std::is_same_v<S<>, S<>>, "This is ridiculous");

Это, кстати, прямо противоречит Сохранению состояний в метапрограммировании на С++?

Ответ 1

Это Активная проблема CWG 2118:

Определение функции друга в шаблоне, а затем ссылка на эту функцию позже предоставляет средство для захвата и получения состояния метапрограммирования. Этот метод является тайным и должен быть плохо сформирован.

Примечания к встрече на май 2015 года:

CWG согласилась с тем, что такие методы должны быть плохо сформированы, хотя механизм их запрещения еще не определен.

Это все еще актуальная проблема, по крайней мере пока ничего не изменится в С++ 17. Хотя, когда такой механизм запрета определен, это может быть ретроактивно управляется как ДР.