2016-12-30 13 views
7

Nó sẽ có thể xác minh rằng một danh sách initializer đang được chuyển đến một nhà xây dựng constexpr là một kích thước nhất định? Hay điều này chỉ có thể thực hiện được khi chạy?Làm thế nào để static_assert rằng một danh sách initializer là một kích thước nhất định

Đây là ý tưởng, nhưng nó không hoạt động:

struct group 
{ 
     constexpr group(
      std::initializer_list<std::initializer_list<UINT const> const> groups 
     ) 
     { 
      static_assert(each_list_size_greater_than_1(groups.begin(), groups.end())); 
     } 

     constexpr static bool each_list_size_greater_than_1(
      std::initializer_list<std::initializer_list<UINT const> const>::const_iterator const begin 
      , std::initializer_list<std::initializer_list<UINT const> const>::const_iterator const end) 
     { 
      return begin == end || begin->size() > 1 && each_list_size_greater_than_1(begin + 1, end); 
     } 
}; 

Tôi đã nhìn std::initializer_list thực hiện VS2015 và begin(), end()size() đều constexpr chức năng.

Trả lời

9

Mặc dù size() của một std::initializer_list<T> có thể đánh giá một constexpr các size() thành viên sẽ không cư xử giống như một constexpr trong vòng một hàm constexpr: đó là cố ý mà các đối tượng chỉ cư xử như constexpr trong biểu constexpr nơi họ đã giới thiệu nhưng không phải ở nơi khác .

Ví dụ:

constexpr get_size(std::initializer_list<int> list) { 
    constexpr std::size_t csize = list.size(); // ERROR (1) 
    std::size_t   size = list.size(); // OK 
    return size; 
} 

int main() { 
    constexpr std::size_t csize = get_size(std::initializer_list<int>{ 1, 2, 3 }); // OK (2) 
    // ... 
} 

Trong trường hợp đầu tiên (1) giá trị đó được giả định để mang lại một constexpr phụ thuộc vào dữ liệu được tạo ra trước khi constexpr khởi động. Kết quả là, nó không đánh giá một constexpr. Trong trường hợp thứ hai (2) dữ liệu được xác định trong constexpr và, do đó, kết quả có thể trở thành một constexpr.

Tôi chưa tham gia vào các cuộc thảo luận dẫn đến thiết kế này nhưng dường như nó được thúc đẩy bởi mong muốn ngăn chặn các đối số constexpr: nếu các giá trị là constexpr s trong định nghĩa hàm, chúng cũng sẽ là constexpr s trong giá trị trả về và do đó, có thể được sử dụng làm đối số mẫu trong kiểu trả về. Điều đó sẽ dẫn đến các giá trị khác nhau cho hàm constexpr năng suất các loại khác nhau. Cho đến nay, bạn chỉ có thể nhận được một kiểu trả về khác bằng cách thay đổi các kiểu đối số của một hàm và/hoặc bằng cách thay đổi số đối số của một hàm.

+0

Điều gì có nghĩa là câu lệnh cuối cùng của bạn: 'Cho đến nay, bạn có thể nhận được loại trả về khác nhau chỉ thay đổi đối số mẫu và/hoặc số của chúng.'? – Adrian

+0

@Adrian: theo tiêu chuẩn C++ ít nhất tối đa C++ 1z, bạn không thể tạo các kiểu trả về khác nhau cho hàm dựa trên _value_ của đối số hàm. Bạn cần thay đổi _type_ của hàm để thay đổi kiểu trả về của hàm. Tôi nhận ra rằng bạn không quan tâm đến việc thực sự thay đổi kiểu trả về của một hàm mà chỉ sử dụng một giá trị đối số như là một 'constexpr'. Tuy nhiên, nếu một giá trị đối số có thể được sử dụng như một 'constexpr' trong một hàm có cùng giá trị có thể được sử dụng trong kiểu trả về, do đó làm cho một cái gì đó có thể hiện không được phép. –

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