2013-05-25 5 views
7

Я пытаюсь определить во время компиляции, если все значения в std::initializer_list уникальны. Я смог найти решение для valiate the size списка, но не смог применить его к содержимому. Я пробовал как с бесплатными функциями, так и с конструкторами, но оба подхода привели к следующим ошибкам с GCC 4.7.2.Подтвердить содержимое std :: initializer_list во время компиляции

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

Я понимаю, что члены std::initializer_list не объявлены constexpr, но я надеюсь, что есть решение, как проверка размера. Можно ли проверять содержимое во время компиляции, используя что-то вроде следующего?

#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

Согласно действующему предложению на [C++ 14] (http://isocpp.org/files/papers/N3690.pdf), 'начать()' и ' end() 'из' std :: initializer_list' будет 'constexpr' в будущем (см. 18.9/1). Это устраняет одно препятствие, но я не уверен, будет ли разыменование значений итератора когда-либо во время компиляции. – jogojapan

+1

@jogojapan: «Итераторы» из 'std :: initializer_list ' просто «T *» - гарантированы. – Xeo

+0

@Xeo Да, и я предположил, что разыменование такого указателя не будет разрешено в постоянном выражении. – jogojapan

ответ

1

После некоторого копания, похоже, используя std::initializer_list является не возможно в GCC 4.7 из-за отсутствия constexpr в его декларации. Он должен работать с GCC 4.8 как <initializer_list> был обновлен, чтобы включить constexpr. К сожалению, использование GCC 4.8 на данный момент не является вариантом.

Доступ к элементам массива возможен, если затухающий указатель передается по ссылке. Это позволяет проводить проверку по желанию, но все же это не совсем то решение, на которое я надеюсь. Следующий код является приемлемым решением для массивов. Он по-прежнему требует, чтобы размер массива был передан функции проверки, но его достаточно легко исправить.

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

.

бревенчатых:

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

Смежные вопросы