2017-01-02 12 views
14

Tôi đã thực hiện một mảng constexpr như thế này:Không thể xây dựng mảng constexpr từ chuẩn bị tinh thần-init-list

template <typename T> 
class const_array { 
    const T* p; 
    unsigned n; 
public: 
    template <unsigned N> 
    constexpr const_array(const T(&a)[N]): p(a), n(N) { } 

    constexpr unsigned size() const { return n; } 
}; 

int main(int argc, char* argv[]) { 
    // works 
    static_assert(const_array<double>{{1.,2.,3.}}.size() == 3); 

    // doesn't compile 
    constexpr const_array<double> a{{1.,2.,3.}}; 
    static_assert(a.size() == 3); 
} 

Tại sao nó rằng static_assert biên dịch đầu tiên, nhưng khởi a thất bại Tôi đang sử dụng gcc 6.2? .0. Tôi đang nhận được

: In function 'int main(int, char**)': 
: error: 'const_array<double>{((const double*)(&<anonymous>)), 3u}' is not a constant expression 
    constexpr const_array<double> a{{1.,2.,3.}}; 
             ^
test/const_array.cc:17:3: error: non-constant condition for static assertion 
    static_assert(a.size() == 3); 
    ^~~~~~~~~~~~~ 
+1

Bạn đã xác định 'a' hai lần. Cũng giống như một chuyển đổi tiềm ẩn có thể xảy ra. Bạn có nhận được bất kỳ cải tiến nào nếu bạn trang trí cho c'tor một cách rõ ràng không? – KyleKnoepfel

+0

@KyleKnoepfel Làm cho hàm tạo rõ ràng không hữu ích. – SU3

+1

'a1' thất bại trong clang với' con trỏ trỏ tới subobject của tạm thời không phải là một biểu thức liên tục'. – jbapple

Trả lời

11

Trình biên dịch phàn nàn rằng trình khởi tạo a.p không phải là biểu thức liên tục. Nó không thành công §5.20/5.2:

nếu giá trị là kiểu con trỏ, nó chứa địa chỉ của một đối tượng có thời gian lưu trữ tĩnh, địa chỉ quá cuối của đối tượng (5.7), địa chỉ của một hàm hoặc giá trị con trỏ null

Nói cách khác, chỉ giá trị con trỏ được biết đến liên kết là các hằng hợp lệ. (Ngoài ra, trong ví dụ của bạn con trỏ đang lơ lửng.)

Đầu tiên static_assert không đi chuyến này bởi vì p bị hủy và giá trị n là biểu thức không đổi. Các biểu thức liên tục có thể có các biểu thức con không liên tục.

này hoạt động:

static constexpr double arr[] = { 1.,2.,3. }; 
constexpr const_array<double> a{ arr }; 
static_assert(a.size() == 3); 

tín dụng để @ Jarod42 để chỉ ra vấn đề này trong các ý kiến.

+1

Tôi không chắc chắn rằng phần đó sẽ áp dụng. Chúng tôi không có một con trỏ giá trị ở bất cứ đâu. Ngoài ra, cả gcc và clang đều cho phép 'static_assert (const_array {{1., 2., 3.}}. P [0] == 1.)' (giả sử bạn tạo 'p' công khai) – Barry

+0

@Barry Vì giá trị của 'a' là một biểu thức không đổi, dấu đầu dòng 3 áp dụng:" nếu giá trị là một đối tượng của kiểu lớp hoặc mảng, mỗi đối tượng con thỏa mãn các ràng buộc này cho giá trị. " 'a.p' là một phần tử con của' a', do đó, dấu đầu dòng 2 áp dụng cho nó. Trong 'static_assert' của bạn, điều kiện' == 1' là một biểu thức không đổi, nhưng ' .p' chỉ là biểu thức con của nó, không được chính nó cho phép dưới dạng biểu thức hằng số. – Potatoswatter

+0

Nhưng 'a' không phải là giá trị chính xác. – Barry

0

Vấn đề là bạn không thể truyền đạt bản chất liên tục của con trỏ tới T trong mẫu bên trong thông qua tham số T của mẫu bên ngoài.

template <typename T> class const_array { 
    const T * p; 
    unsigned n; 
public: 
    template <unsigned N> 
     constexpr const_array(const T(& a)[N]): p(a), n(N) { } 
}; 

int main(int argc, char* argv[]) { 
    constexpr const_array<double> ca{(const double []) { 1., 2. }}; 
    return 0; 
} 

Tôi đã thử vài chục hoán vị để loại bỏ diễn viên mà không thành công.

+1

Điều này không trả lời được câu hỏi. – Barry

+0

@Barry, Đúng vậy. Cả hai lỗi trong câu hỏi liên quan đến thực tế là con trỏ tới T không phải là hằng số trong khuôn mẫu bên ngoài để trình biên dịch không thể tìm thấy khuôn mẫu bên trong và không có cấu trúc nào đảm bảo hằng số của con trỏ tới T khi truyền T. Nó sẽ là không phù hợp (một hack xấu) để làm điều đó trong khuôn mẫu bên ngoài chỉ để buộc trận đấu. – FauChristian

+0

@FauChristian "Cả hai"? Có một lỗi trong câu hỏi. – Barry

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