2016-06-05 13 views
2

ich diesen Code in Verbindung zu SFINAE gefunden:Seltsam SFINAE Code

template<int I> void div(char(*)[I % 2 == 0] = 0) { 
    // this overload is selected when I is even 
} 
template<int I> void div(char(*)[I % 2 == 1] = 0) { 
    // this overload is selected when I is odd 
} 

Wie funktioniert es? Es sieht wie ein unbenanntes Parameter-Array aus, aber ich verstehe nicht, wie das Subskript bei der Überladungsauflösung hilft.

Antwort

6

Array-Grenzen in C++ können nicht null sein. Wenn der Ausdruck (z. B. I % 2 == 0) false ist, wird dieser Wert in Null konvertiert, was zu einem ungültigen Typ und daher zu einem Substitutionsfehler führt.

Im Wesentlichen ist es eine verschleierte Version von std::enable_if.

1

Denken Sie daran, dies heißt so: div<1234>() => erste Überlastung wird aufgerufen.

Um verstehen Sie das Argument untersuchen müssen nur:

char(*)[I % 2 == 0] = 0 Dies bedeutet, es Zeiger auf ein Array von Zeichen ist. Dieses Array hat den Standardwert 0. Das heißt, Sie könnten auch char a[] = "hello world"; div<1234>(a);

I % 2 == 0 wird zur Kompilierzeit ausgewertet. Sie sollten wissen, was es tut. Gerade ganze Zahlen machen dies wahr, ungerade ganze Zahlen machen dies falsch. True ergibt 1, false ergibt 0. Es gibt jedoch kein Array mit null Elementen. Dies nennen Sie einen SFINAE-Fehler. Es bedeutet nicht, dass es sich um einen fundamentalen Fehler handelt, nur dass die Lücken in der Schablone nicht adäquat ersetzt werden konnten. Die Vorlage stimmt nicht mit überein.

0

Wie von T.C. Da Sie keine Arrays mit 0 Elementen haben können, wenn die Bedingung false ist, wird der boolesche Wert false in 0 konvertiert: Der Typ wird char (*) [0] (Zeiger auf ein char-Array der Größe 0) und dies löst SFINAE aus.

nun in einer konventionelleren (und lesbar) Art und Weise, würden Sie in der Regel lassen std::enable_if die Arbeit machen:

template <int I, std::enable_if_t<I%2>* = nullptr> 
div() { 
    std::cout << "I (" << I <<") am odd." << std::endl; 
} 

template <int I, std::enable_if_t<!(I%2)>* = nullptr> 
div() { 
    std::cout << "I (" << I <<") am even." << std::endl; 
} 

Wie auf Coliru hier demonstriert.