2013-05-25 12 views
7

Próbuję określić w czasie kompilacji, czy wszystkie wartości w std::initializer_list są unikatowe. Udało mi się znaleźć rozwiązanie na liście o nazwie valiate the size, ale nie udało się zastosować go do zawartości. Próbowałem zarówno z funkcjami darmowymi, jak i konstruktorami, ale oba podejścia spowodowały następujące błędy w GCC 4.7.2.Sprawdzanie poprawności zawartości std :: initializer_list podczas kompilacji

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

Zdaję sobie sprawę członkowie std::initializer_list nie są zadeklarowane constexpr ale mam nadzieję, że jest to rozwiązanie jak zatwierdzania wielkości. Czy możliwe jest sprawdzenie poprawności zawartości podczas kompilacji za pomocą czegoś podobnego?

#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

Według obecnego wniosku dotyczącego [C++ 14] (http://isocpp.org/files/papers/N3690.pdf), 'begin()' i ' end() 'of' std :: initializer_list' będzie w przyszłości 'constexpr' (patrz 18.9/1). To usuwa jedną przeszkodę, ale nie jestem pewien, czy usunięcie wartości iteratora kiedykolwiek będzie możliwe podczas kompilacji. – jogojapan

+1

@jogojapan: "Iteratory" z 'std :: initializer_list ' są po prostu 'T *' - gwarantowane. – Xeo

+0

@Xeo Tak, i założyłem, że dereferencja takiego wskaźnika nie będzie dozwolona w stałym wyrażeniu. – jogojapan

Odpowiedz

1

Po niektóre kopania wygląda użyciu std::initializer_list jest nie możliwe w GCC 4.7 ze względu na brak constexpr w deklaracji jest to. To powinien współpracować z GCC 4.8 jako <initializer_list> został zaktualizowany o constexpr. Niestety używanie GCC 4.8 nie jest obecnie możliwe.

Możliwe jest uzyskanie dostępu do elementów tablicy, jeśli zepsuty wskaźnik jest przekazywany przez odwołanie. Dzięki temu walidacja może nastąpić zgodnie z oczekiwaniami, ale nadal nie jest to rozwiązanie, na które mam nadzieję. Poniższy kod jest praktycznym rozwiązaniem dla tablic. Nadal wymaga, aby rozmiar tablicy był dostarczany do funkcji sprawdzania poprawności, ale jest to łatwe do poprawienia.

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

.

dziennika budowy:

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

Powiązane problemy