2013-05-25 8 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)のための現在の提案によれば、 '')(開始と ' 'std :: initializer_list'の' end() 'は' constexpr'になります(18.9/1参照)。 1つの障害が取り除かれますが、コンパイル時に反復子値の逆参照が可能かどうかはわかりません。 – jogojapan

+1

@ jogojapan: 'std :: initializer_list 'の「イテレータ」は 'T *' - 保証されています。 – Xeo

+0

@Xeoはい、私はそのようなポインタの逆参照は定数式では許されないと仮定しました。 – jogojapan

答えて

1

std::initializer_listを使用するため、それの宣言でconstexprの欠如にGCC 4.7で可能なないように見える掘ります。 <initializer_list>としてconstexprを含むように更新されているため、GCC 4.8で動作するはずです。残念ながら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

関連する問題