2013-05-25 11 views
7

Sto tentando di determinare in fase di compilazione se tutti i valori in un std::initializer_list sono univoci. Sono stato in grado di individuare una soluzione a valiate the size di un elenco ma non è stato possibile applicarlo ai contenuti. Ho provato con entrambe le funzioni libere e nei costruttori ma entrambi gli approcci hanno provocato i seguenti errori con GCC 4.7.2.Convalida il contenuto di std :: initializer_list al momento della compilazione

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

mi rendo conto dei membri del std::initializer_list non vengono dichiarati constexpr ma spero ci sia una soluzione come la convalida dimensioni. È possibile convalidare i contenuti al momento della compilazione usando qualcosa come il seguente?

#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

Secondo l'attuale proposta di [C++ 14] (http://isocpp.org/files/papers/N3690.pdf), 'begin()' e ' end() 'di' std :: initializer_list' sarà 'constexpr' in futuro (vedi 18.9/1). Ciò rimuove un ostacolo, ma non sono sicuro che il dereferenziamento dei valori degli iteratori sarà mai possibile in fase di compilazione. – jogojapan

+1

@jogojapan: Gli "iteratori" di una 'std :: initializer_list ' sono solo 'T *' - garantiti. – Xeo

+0

@Xeo Sì, e ho assunto che il dereferenziamento di un puntatore del genere non fosse consentito in un'espressione costante. – jogojapan

risposta

1

Dopo un po 'di scavo sembra usando std::initializer_list è non possibile nel GCC 4.7 a causa della mancanza di constexpr in esso di dichiarazione. È dovrebbe funzionare con GCC 4.8 come <initializer_list> è stato aggiornato per includere constexpr. Sfortunatamente l'utilizzo di GCC 4.8 non è un'opzione al momento.

È possibile accedere agli elementi di un array se il puntatore decaduto viene passato per riferimento. Ciò consente alla convalida di presentarsi come desiderato ma non è ancora la soluzione che spero. Il seguente codice è una soluzione praticabile per gli array. Richiede comunque che la dimensione dell'array sia fornita alla funzione di convalida, ma che sia abbastanza facile da correggere.

#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"); 
} 

.

registro

Corporatura:

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

Problemi correlati