Jednym z moich najbardziej ukochanych/złych wynalazków, z którymi miałem do czynienia, jest constexpr counter, czyli metaprogramowanie w stanie stanowym. Jak wspomniano w poście, wydaje się być legalne pod C++ 14 i zastanawiam się czy coś zmieniło się w C++ 17?Czy stanowe metaprogramowanie jest źle sformułowane (jeszcze)?
Poniżej jest realizacja w dużej mierze opiera się na stanowisku
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;
}
I use it jak
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");
To nawiasem mówiąc, jest bezpośrednim zaprzeczeniem Storing States in C++ Metaprogramming?
W jaki sposób 'odczyt (0, flaga {})' nie powoduje nieskończonej pętli? Dosłowne 0 powoduje, że wywołuje pierwsze przeciążenie ('int' jest preferowane w porównaniu z' float'), które naturalnie wywoła to ponownie i znowu i znowu. Co to jest warunek zakończenia? –
@NicolBolas Przez SFINAE, przeciążenie 'int'' read (0, flag {}) 'nie może być wywołane dla jakiegoś wystarczająco dużego' N', ponieważ nie zdefiniowaliśmy jeszcze 'adl_flag (flag )', dlatego ' Nadmierne obciążenie byłoby wywołane. Aby uzyskać pełne wyjaśnienie, połączony post został napisany znakomicie. –
Zwróć także uwagę na błędy wskazane przez Davida Kraussa w odpowiednim temacie [std-discussion] (https://groups.google.com/a/isocpp.org/d/msg/std-discussion/M6aJMH_ewoM/eAaBooYw-MsJ) , które Filip obiecał wypowiedzieć w czwartym poście, ale nigdy tego nie zrobił. – Columbo