15

ich an diesem Quellcode freu-Code Ich habe noch nie in 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]; 

gesehen und ich frage mich, ob dies überhaupt gültig C++.

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

Was ist das? Eine Template-Spezialisierung, die nicht spezialisiert ist?

Und warum eine Strukturdeklaration im Inneren hat Codezeilen wie

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

Ich bin verwirrt ..

+0

Ja, Entschuldigung für den Fehler – Paul

+2

Werfen Sie einen Blick auf diese Links. Sie sollten alles erklären. - [Variadic Templates] (http://www.cplusplus.com/articles/EhvU7k9E/) - [Benutzerdefinierte Literale] (http://en.cppreference.com/w/cpp/language/user_literal) - [Statisch Behauptung] (http://en.cppreference.com/w/cpp/language/static_assert) –

Antwort

22

Ihr Code zeigt drei neue C++ 11 Funktionen: variadische Vorlagen, Benutzerdefinierte Literale und statische Aussagen.

Die allgemeine variadic Klassenvorlage spezifiziert null oder mehr Argumente, die spezialisierten Versionen eins oder mehrere und genau eins.

// 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> 

Die vollständige Syntax von variadische Vorlagen ist ein wenig schrullig, Wikipedia auf es einen ordentlichen Artikel hat. Es ist besonders nützlich für ein anderes C++ 11-Feature: perfekte Weiterleitung einer variadic Anzahl von Funktionsargumenten.

Das exotisch aussehende int operator "" _b() definiert ein benutzerdefiniertes Literal, mit dem Sie Ihren Typen und Ausdrücken eigene Einheiten hinzufügen können. Es bedeutet einfach, dass ganze Zahlen gefolgt von _b mit einer bestimmten "Einheit" markiert sind. Siehe hierzu question für weitere Details. Ein praktischer Vorteil wäre, zukünftige Mars Lander Crashes zu vermeiden (wo SI und imperiale Einheiten in ihrer Landing Software gemischt wurden, ohne dass der Compiler dies diagnostizieren konnte).

Die static_assert tut genau das, was Sie denken, es tut: es behauptet seinen Zustand statisch, d. H. Bei kompilieren-Zeit. Wenn die Assertion fehlschlägt, wird die Kompilierung angehalten. Dies ist eine großartige Möglichkeit, Fehler so schnell wie möglich zu erkennen.

UPDATE

Spezialisierung von variadische Vorlagen sehr überraschend sein kann, wenn Sie teilweise überlappende Bereiche der Argumente haben: die null oder mehr Argumente Version wird nur eine leere Liste passen in Ihrem Beispiel (im Fall würden Sie haben eine Definition dafür gegeben).

#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! 
} 

Ausgabe auf LiveWorkSpace.

Das ist natürlich ein Beispiel für die allgemeine Regel für die partielle Template-Spezialisierung, die besagt, dass die spezialisierteste Version wird ausgewählt werden (ein oder-mehr ist spezialisierter als Null-oder-mehr, da diese Dose immer dort verwendet werden, wo das erstere möglich ist, aber nicht umgekehrt). Aber weil variadische Vorlagen sich oft nicht so "sichtbar" voneinander unterscheiden, sollten Sie mit ihren Teilspezialisierungen besonders vorsichtig sein.

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

Dies ist eine Vorlagen-Forward-Deklaration. Es muss nicht vollständig definiert werden, da Sie den Fehler früher finden, wenn er nicht unterstützt wird (die Kompilierung wird fehlschlagen). Dieses spezielle Beispiel führt nicht dazu, dass die Kompilierung fehlschlägt, da die Spezialisierungen alle möglichen Fälle abdecken.

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; 
}; 

Dies ist eine Teilspezialisierung, bei der ein Vorlagenwert festgelegt wird. Der Rest wird nur auf die "untere Ebene" des Vorlagentyps weitergeleitet. Diese Vorlagenstruktur ist vollständig definiert und enthält eine int-Elementvariable, deren Wert vom Wert 'high' und der nächsten Vorlage abhängt.

Erneut partielle Template-Spezialisierung, die den Wert definiert, wenn die Template-Parameter nur einen Parameter in der Liste enthalten.

Also, insgesamt ist dies ein template meta-programming mit variadic Vorlagen.


Die statischen Annahmen sind da, um die Werte zu begrenzen, die Vorlagenvariablen annehmen können.