2017-12-08 137 views
8

Mam dwa (lub więcej) szablonów, z których każdy może dostosować określony zestaw klas, zidentyfikowany przez koncepcję. Aby oba szablony miały taką samą nazwę, muszą należeć do specjalizacji.Koncepcje C++ i specjalizacja szablonów; jak uzyskać przyjazny dla użytkownika błąd kompilatora

template< typename T > 
struct pin_in { static_assert(always_false<T>::value, . . .); }; 

template< is_pin_in T > 
struct pin_in<T> . . . 

template< is_pin_in_out T > 
struct pin_in<T> . . . 

Działa to poprawnie, gdy jedna z specjalizacji jest zgodna. Jeśli żadna nie pasuje do szablonu podstawowego, zostanie wybrana awaria asercji. Mechanizm działa. Kocham pojęcia!

Ale komunikat o błędzie, który otrzymuję (GCC 7.2.0) wskazuje na potwierdzenie. Czy mogę w jakiś sposób uniemożliwić wybór szablonu podstawowego, więc otrzymam komunikat o błędzie informujący, że żaden szablon nie pasuje do klasy argumentów?

+0

Dlaczego nie możesz dodać komunikatu (drugi argument) do statycznego dowodu tożsamości? –

+0

Oczywiście, że mam, to jest. . . Ale główny komunikat o błędzie nadal wskazuje na potwierdzenie, a nie na linię, która go spowodowała. –

+0

Kompilator czasami dodaje ślad wsteczny w postaci _in tworzenia instancji Object_ i _required from here_, gdzie wskazuje, gdzie miały miejsce instancje. –

Odpowiedz

2

Hurra, znalazłem rozwiązanie! Co potrzebne jest, że główny szablon ograniczane:

template <class T> 
    requires is_pin_in<T> || is_pin_in_out<T> 
struct pin_in {}; 


template <is_pin_in T> 
struct pin_in<T> {}; 

template <is_pin_in_out T> 
struct pin_in<T> {}; 

I masz dobrą wiadomość diagnostyczne:

<source>: In function 'auto test()': 
29 : <source>:29:16: error: template constraint failure 
    pin_in<char> a; 
       ^
29 : <source>:29:16: note: constraints not satisfied 
7 : <source>:7:24: note: within 'template<class T> concept const bool is_pin_in<T> [with T = char]' 
constexpr concept bool is_pin_in = std::is_same_v<T, int>; 
         ^~~~~~~~~ 
7 : <source>:7:24: note: 'std::is_same_v' evaluated to false 
9 : <source>:9:24: note: within 'template<class T> concept const bool is_pin_in_out<T> [with T = char]' 
constexpr concept bool is_pin_in_out = std::is_same_v<T, unsigned>; 
         ^~~~~~~~~~~~~ 
9 : <source>:9:24: note: 'std::is_same_v' evaluated to false 
Compiler exited with result code 1 

dobrze, moja wiadomość jest z pewnych pozornych ograniczeń, ale można dostać punkt

+0

Nice! Koncepcje na ratunek. –

+0

Ale jest jeden mały problem: to rozwiązanie jest zamknięte w tym sensie, że nie mogę później dodać specjalizacji, powiedzmy, is_pin_foo bez zmiany szablonu podstawowego. Ale typ znacznika w klasach, które są dopuszczalne, może rozwiązać ten problem. Ale może to spowodować odwrotny problem: szablon dekoratora napisany później będzie musiał uzupełnić istniejące klasy swoim znacznikiem. Chyba że wyliczyłoby ich w wymaganiach ... Bawię się tym! –

+0

@WoutervanOoijen Chciałbym po prostu stworzyć koncepcję, która ma sens dla 'pin_in'. Na przykład. 'szablon pojęcie boxy constexpr is_any_pin_in = is_pin_in || is_pin_in_out ' – bolov

0

Spróbuj użyć std :: enable_if, aby usunąć szablon podstawowy z rozdzielczości przeciążenia. Coś takiego:

template< typename T > 
struct pin_in<typename std::enable_if<false>::type> {}; 

template< is_pin_in T > 
struct pin_in<typename std::enable_if<true>::type><T> . . . 

template< is_pin_in_out T > 
struct pin_in<typename std::enable_if<true>::type><T> . . . 
+0

To jest coś, na co się natknąłem, ale daje błąd na pierwszym pin_in: 'pin_in nie jest szablonem klasy' –