2017-05-30 78 views
34

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?

+0

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? –

+1

@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. –

+2

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

Odpowiedz

31

to CWG active issue 2118 :

Definiowanie funkcji znajomego w szablonie, a odwołanie się do tej funkcji później umożliwia przechwytywanie i pobieranie stanu metaprogramowania. Ta technika jest tajemna i powinna zostać źle sformułowana.

Notatki z maja, 2015 Spotkanie:

CWG zgodzili się, że takie techniki powinny być źle sformułowane, choć mechanizm ich zakazanie jest jeszcze nieokreślony.

To wciąż aktywny problem, na razie nic się nie zmieni w C++ 17. Chociaż, gdy zostanie określony taki mechanizm zakazu, może on być z mocą wsteczną uznany za DR.