2013-05-25 27 views
7

Tôi đang cố gắng xác định thời gian biên dịch nếu tất cả các giá trị trong một std::initializer_list là duy nhất. Tôi đã có thể tìm một giải pháp cho valiate the size của một danh sách nhưng không thể áp dụng nó cho nội dung. Tôi đã thử với cả hai chức năng miễn phí và trong các nhà xây dựng nhưng cả hai cách tiếp cận đã dẫn đến các lỗi sau với GCC 4.7.2.Xác thực nội dung của std :: initializer_list tại thời gian biên dịch

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

Tôi nhận ra các thành viên của std::initializer_list không tuyên bố constexpr nhưng tôi hy vọng có một giải pháp như xác nhận kích thước. Có thể xác thực các nội dung tại thời gian biên dịch bằng cách sử dụng một cái gì đó như sau?

#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

Theo đề xuất hiện tại cho [C++ 14] (http://isocpp.org/files/papers/N3690.pdf), 'bắt đầu()' và ' end() 'của' std :: initializer_list' sẽ là 'constexpr' trong tương lai (xem 18.9/1). Điều đó loại bỏ một trở ngại, nhưng tôi không chắc chắn liệu dereferencing các giá trị lặp sẽ bao giờ có thể tại thời gian biên dịch. – jogojapan

+1

@jogojapan: Các "trình lặp" của một 'std :: initializer_list ' chỉ là 'T *' - được bảo đảm. – Xeo

+0

@Xeo Có, và tôi giả định rằng dereferencing như một con trỏ sẽ không được phép trong một biểu thức liên tục. – jogojapan

Trả lời

1

Sau khi một số đào nó trông giống như sử dụng std::initializer_listkhông thể trong GCC 4.7 do thiếu constexpr trong việc kê khai của nó. Nó nên hoạt động với GCC 4.8 là <initializer_list> đã được cập nhật để bao gồm constexpr. Thật không may bằng cách sử dụng GCC 4.8 không phải là một lựa chọn tại thời điểm này.

Có thể truy cập các phần tử của một mảng nếu con trỏ bị phân rã được truyền qua tham chiếu. Điều này cho phép xác thực xảy ra như mong muốn nhưng vẫn không hoàn toàn là giải pháp mà tôi hy vọng. Mã sau đây là một giải pháp khả thi cho các mảng. Nó vẫn yêu cầu kích thước của mảng được cung cấp cho hàm xác nhận nhưng nó đủ dễ sửa.

#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

Các vấn đề liên quan