15

Patrzę na tym kodzie źródłowymKod nigdy nie widziałam w C++ 11

template<char... digits> 
struct conv2bin; 

template<char high, char... digits> 
struct conv2bin<high, digits...> { 
    static_assert(high == '0' || high == '1', "no bin num!"); 
    static int const value = (high - '0') * (1 << sizeof...(digits)) + 
          conv2bin<digits...>::value; 
}; 

template<char high> 
struct conv2bin<high> { 
    static_assert(high == '0' || high == '1', "no bin num!"); 
    static int const value = (high - '0'); 
}; 

template<char... digits> 
constexpr int operator "" _b() { 
    return conv2bin<digits...>::value; 
} 

int array[1010_b]; 

i zastanawiam się, czy to jest jeszcze ważny C++.

template<char high, char... digits> 
struct conv2bin<high, digits...> { 

Co to jest? Specjalizacja szablonu, która nie specjalizuje się?

I dlaczego deklaracja struct ma linii kodu wewnątrz niego jak

struct conv2bin<high> { 
    static_assert(high == '0' || high == '1', "no bin num!"); 
    static int const value = (high - '0'); 
}; 

jestem zdezorientowany ..

+0

Przepraszam za błąd – Paul

+2

Zobacz te linki. Powinny wszystko wyjaśnić. - [Variadic Templates] (http://www.cplusplus.com/articles/EhvU7k9E/) - [User-Defined Literals] (http://en.cppreference.com/w/cpp/language/user_literal) - [Static Asercja] (http://en.cppreference.com/w/cpp/language/static_assert) –

Odpowiedz

22

Twój kod przedstawia trzy nowe C++ 11 funkcje: o zmiennej liczbie argumentów szablony, zdefiniowane przez użytkownika literały i asercje statyczne.

Ogólny szablon klasy variadic określa zero lub więcej argumentów, wyspecjalizowane wersje, odpowiednio, jeden lub więcej i dokładnie jeden.

// digits can be the empty set, so 0 or more arguments 
template<char... digits> 
struct conv2bin; 

// digits can be the empty set, so 1 or more arguments 
template<char high, char... digits> 
struct conv2bin<high, digits...> 

// fully specialized for 1 argument 
template<char high> 
struct conv2bin<high> 

Pełna składnia zmiennej liczbie argumentów szablonów jest nieco ekscentryczny, Wikipedia ma przyzwoitą artykuł o nim. Jest to szczególnie użyteczne dla innej funkcji C++ 11: perfekcyjne przekazywanie z variadycznej liczby argumentów funkcji.

Egzotycznie wyglądający int operator "" _b() definiuje zdefiniowany przez użytkownika tekst, który jest sposobem dodawania własnych jednostek do typów i wyrazów. Oznacza to po prostu, że liczby całkowite, po których następuje _b, są oznaczone pewną "jednostką". Więcej informacji można znaleźć w tej wersji: question. Jedną z praktycznych korzyści byłoby uniknięcie przyszłych awarii lądownika Marsa (gdzie jednostki SI i imperialne były miksowane w oprogramowaniu do lądowania, bez możliwości ich zdiagnozowania przez kompilator).

Wykonuje dokładnie to, o czym myśli: statycznie, tzn. Pod podczas kompilacji. Gdy asercja nie powiedzie się, kompilacja zostanie zatrzymana. To doskonały sposób na wykrycie błędów tak szybko, jak to możliwe.

UPDATE

Specjalizacja o zmiennej liczbie argumentów szablony mogą być bardzo zaskakujące, gdy masz częściowo pokrywających się zakresów argumentów: Wersja zero lub więcej argumentów będzie pasować tylko pustą listę w swoim przykładzie (w przypadku, gdy będzie podałem definicję).

#include <iostream> 

template<int... Args> 
struct Test 
{ 
    enum { value = 0 }; 
}; 

template<int I, int... Args> 
struct Test<I, Args...> 
{ 
    enum { value = 2 }; 
}; 

template<int I> 
struct Test<I> 
{ 
    enum { value = 1 }; 
}; 

int main() 
{ 
    std::cout << Test<>::value << "\n";  // matches zero or more version 
    std::cout << Test<0>::value << "\n"; // matches single argument version 
    std::cout << Test<0, 0>::value << "\n"; // matches one or more version, not the zero or more one! 
} 

Wyjście na LiveWorkSpace.

To oczywiście przykładem reguły częściowego specjalizacji szablon, który stwierdza, że ​​najbardziej lowieniem zostanie wybrany (jeden albo, jeszcze bardziej wyspecjalizowane niż zero lub, więcej, ponieważ może on zawsze należy używać tam, gdzie może to zrobić, ale nie na odwrót). Ale ponieważ szablony variadyczne często nie są tak "wyraźnie" różne od siebie, powinieneś zachować szczególną ostrożność w swoich częściowych specjalizacjach.

1
template<char... digits> 
struct conv2bin; 

To jest szablon zgłoszenia do przodu. Nie musi być w pełni zdefiniowana, ponieważ jeśli jest używana w nieobsługiwany sposób, szybciej zauważysz błąd (kompilacja się nie powiedzie). Ten konkretny przykład nie doprowadzi do niepowodzenia kompilacji, ponieważ specjalizacje obejmują wszystkie możliwe przypadki.

template<char high, char... digits> 
struct conv2bin<high, digits...> { 
    static_assert(high == '0' || high == '1', "no bin num!"); 
    static int const value = (high - '0') * (1 << sizeof...(digits)) + 
          conv2bin<digits...>::value; 
}; 

Jest to specjalizacja częściowa, w której ustawiono jedną wartość szablonu. Reszta jest po prostu przekazywana do "niższego poziomu" typu szablonu. Ta struktura szablonu jest w pełni zdefiniowana i zawiera zmienną składową int, której wartość zależy od "wysokiej" wartości i następnego szablonu.

template<char high> 
struct conv2bin<high> { 
    static_assert(high == '0' || high == '1', "no bin num!"); 
    static int const value = (high - '0'); 
}; 

Ponownie częściowa specjalizacja szablonu, określając wartość, gdy parametry szablonu zawiera tylko jeden parametr w to jest lista.

W sumie jest to template meta-programming przy użyciu szablonów variadic.


Statyczne asserts mają na celu ograniczenie wartości, które mogą przyjmować zmienne szablonu.