2013-05-25 7 views
7

Ich versuche zur Kompilierzeit festzustellen, ob alle Werte in einer std::initializer_list eindeutig sind. Ich konnte eine Lösung zu valiate the size einer Liste finden, aber konnte es nicht auf den Inhalt anwenden. Ich habe sowohl mit freien Funktionen als auch mit Konstruktoren versucht, aber beide Ansätze haben zu folgenden Fehlern mit GCC 4.7.2 geführt.Validiere den Inhalt von std :: initializer_list zur Kompilierzeit

error: non-constant condition for static assertion
error: 'begin' is not a constant expression

erkenne ich die Mitglieder der std::initializer_list nicht constexpr erklärt aber ich hoffe, es gibt eine Lösung wie die Größe Validierung ist. Ist es möglich, den Inhalt zur Kompilierzeit zu validieren, indem Sie Folgendes verwenden?

#include <initializer_list> 

template<typename InputIterator> 
constexpr bool Validate(InputIterator begin, InputIterator end) 
{ 
    static_assert(*begin == *end, "begin and end are the same"); 
    // The actual implemetnation is a single line recursive check. 
    return true; 
} 

template<typename InputType> 
constexpr bool Validate(const std::initializer_list<InputType>& input) 
{ 
    // "-1" removed to simplify and eliminate potential cause of error 
    return Validate(input.begin(), input.end() /* - 1 */); 
} 

int main() 
{ 
    Validate({1, 2, 1}); 
} 
+2

Nach dem derzeitigen Vorschlag für [C++ 14] (http://isocpp.org/files/papers/N3690.pdf), 'begin()' und ' end() 'von' std :: initializer_list' wird in Zukunft 'constexpr' sein (siehe 18.9/1). Das beseitigt ein Hindernis, aber ich bin nicht sicher, ob die Dereferenzierung der Iteratorwerte jemals zur Kompilierzeit möglich sein wird. – jogojapan

+1

@jogojapan: Die "Iteratoren" einer 'std :: initializer_list ' sind nur 'T *' - garantiert. – Xeo

+0

@Xeo Ja, und ich nahm an, dass die Dereferenzierung eines solchen Zeigers in einem konstanten Ausdruck nicht erlaubt wäre. – jogojapan

Antwort

1

Nach einigem Gräbt es wie mit std::initializer_list aussieht, ist nicht möglich in GCC 4.7 aufgrund des Fehlen von constexpr in seiner Erklärung. Es sollte arbeiten mit GCC 4.8 als <initializer_list> wurde aktualisiert, um constexpr enthalten. Leider ist die Verwendung von GCC 4.8 im Moment keine Option.

Es ist möglich, auf Elemente eines Arrays zuzugreifen, wenn der verfallene Zeiger durch Referenz übergeben wird. Dadurch kann die Validierung wie gewünscht durchgeführt werden, ist aber immer noch nicht die Lösung, auf die ich hoffe. Der folgende Code ist eine praktikable Lösung für Arrays. Es erfordert weiterhin, dass die Größe des Arrays an die Validierungsfunktion geliefert wird, dass es jedoch leicht genug ist, sie zu korrigieren.

#include <initializer_list> 

template<typename T> 
constexpr bool Compare(T& data, int size, int needleIndex, int haystackIndex) 
{ 
    return 
     needleIndex == haystackIndex ? 
      Compare(data, size, needleIndex + 1, haystackIndex) 
     : needleIndex == size ? 
       false 
      : data[needleIndex] == data[haystackIndex] ? 
        true 
       : Compare(data, size, needleIndex + 1, haystackIndex); 
} 

template<typename T> 
constexpr bool Compare(T& data, int size, int index) 
{ 
    return 
     index == size ? 
      false 
     : Compare(data, size, index + 1) ? 
       true 
      : Compare(data, size, 0, index); 
} 


template<typename T, int ArraySize> 
constexpr bool Validate(T(&input)[ArraySize], int size) 
{ 
    return !Compare(input, size, 0); 
} 

int main() 
{ 
    constexpr int initData0[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 
    constexpr int initData1[] = {1, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 
    constexpr int initData2[] = {2, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 
    constexpr int initData3[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 8}; 
    constexpr int initData4[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 7}; 
    constexpr int initData5[] = {0, 1, 0, 3, 4, 5, 6, 7, 8, 9}; 
    constexpr int initData6[] = {0, 1, 2, 3, 4, 5, 6, 9, 8, 9}; 

    static_assert(Validate(initData0, 10), "set 0 failed"); // <-- PASS 
    static_assert(Validate(initData1, 10), "set 1 failed"); // <-- (and below) FAIL 
    static_assert(Validate(initData2, 10), "set 2 failed"); 
    static_assert(Validate(initData3, 10), "set 3 failed"); 
    static_assert(Validate(initData4, 10), "set 4 failed"); 
    static_assert(Validate(initData5, 10), "set 5 failed"); 
    static_assert(Validate(initData6, 10), "set 6 failed"); 
} 

.

Build-Log:

C:\Source\SwitchCaseString\main.cpp: In function 'int main()':
C:\Source\SwitchCaseString\main.cpp:198:2: error: static assertion failed: set 1 failed
C:\Source\SwitchCaseString\main.cpp:199:2: error: static assertion failed: set 2 failed
C:\Source\SwitchCaseString\main.cpp:200:2: error: static assertion failed: set 3 failed
C:\Source\SwitchCaseString\main.cpp:201:2: error: static assertion failed: set 4 failed
C:\Source\SwitchCaseString\main.cpp:202:2: error: static assertion failed: set 5 failed
C:\Source\SwitchCaseString\main.cpp:203:2: error: static assertion failed: set 6 failed