Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Validate contents of std::initializer_list at compile time

I am attempting to determine at compile time if all the values in a std::initializer_list are unique. I was able to locate a solution to valiate the size of a list but have been unable to apply it to the contents. I have tried with both free functions and in constructors but both approaches have resulted in the following errors with GCC 4.7.2.

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

I realize the members of std::initializer_list are not declared constexpr but I'm hoping there is a solution like the size validation. Is it possible to validate the contents at compile time using something like the following?

#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});
}
like image 213
Captain Obvlious Avatar asked May 25 '13 04:05

Captain Obvlious


1 Answers

After some digging it looks like using std::initializer_list is not possible in GCC 4.7 due to the lack of constexpr in it's declaration. It should work with GCC 4.8 as <initializer_list> has been updated to include constexpr. Unfortunately using GCC 4.8 is not an option at the moment.

It is possible to access elements of an array if the decayed pointer is passed by reference though. This allows the validation to occur as desired but still isn't quite the solution I am hoping for. The following code is a workable solution for arrays. It still requires that the size of the array be supplied to the validation function but that it easy enough to correct.

#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

like image 60
Captain Obvlious Avatar answered Oct 15 '22 07:10

Captain Obvlious