2015-07-15 20 views
7

Với g ++ - 5 tôi nhận được kết quả như sauLỗi khi kiểm tra nếu một tuple tài liệu tham khảo là mặc định constructible

#include <type_traits> 
#include <tuple> 
int main() 
{ 
    bool b; 
    b = std::is_default_constructible<int>::value; //Compiles, returns true 
    b = std::is_default_constructible<int&>::value; //Compiles, returns false 
    b = std::is_default_constructible< std::tuple<int> >::value; //Compiles, returns true 
    b = std::is_default_constructible< std::tuple<int&> >::value; //Does not compile 
} 

Đây có phải là một lỗi trong is_default_constructible 's thực hiện?

Các thông báo lỗi là một danh sách ngăn xếp dài kết thúc bằng:

/usr/bin/../lib/gcc/x86_64-linux-gnu/5.1.0/../../../../include/c++/5.1.0/tuple:105:9: error: reference to type 'int' requires an initializer 
    : _M_head_impl() { } 
+0

Thông báo lỗi là gì? –

+0

Chỉnh sửa nó trong @MaximEgorushkin :-) – user3559888

+0

Tôi tự hỏi làm thế nào cơ thể của một nhà xây dựng đã được đánh giá trong trường hợp đó, nhưng không phải trong một đơn giản 'mẫu struct test {T t; test(): t();}; 'trường hợp. Hấp dẫn. – Yakk

Trả lời

7

Đây là không một lỗi trong is_default_constructible. Tính trạng kiểu đó chỉ được yêu cầu để kiểm tra bối cảnh ngay lập tức của việc xây dựng mặc định, nó không phải đánh giá sâu sắc bất kỳ bộ khởi tạo thành viên nào. Hạn chế này có lẽ là để nó có thể được thực hiện mà không có phép thuật biên dịch chuyên dụng bằng cách sử dụng SFINAE. (xem [meta.unary.prop], đặc biệt là p7).

Các nhà thầu mặc định tuplepair không được yêu cầu thất bại trong bối cảnh ngay lập tức (SFINAE thân thiện) nếu loại phần tử không thể được xây dựng mặc định. Điều này đã được giải quyết bằng LWG 2367, trong đó giới thiệu các yêu cầu SFINAE sau cho các nhà xây dựng tuple mặc định:

Ghi chú: constructor này sẽ không tham gia vào giải quyết tình trạng quá tải trừ is_default_constructible<Ti>::value là đúng cho tất cả i. [...]

Với yêu cầu này bổ sung, xây dựng mặc định của một tuple phải thất bại trong một cách SFINAE thân thiện, chẳng hạn rằng is_default_constructible hiện đang làm việc cho tuple nếu các yếu tố không được mặc định-xây dựng trong bối cảnh ngay lập tức (đó là trường hợp cho các loại tài liệu tham khảo).

LWG 2367 hiện đang ở trạng thái Sẵn sàng; nghị quyết được đề xuất chưa được đưa vào các bản nháp github.


[- phần này vẫn đang được xem xét

Yakk giơ một điểm quan trọng trong các ý kiến: Tại sao is_default_constructible phải nhanh chóng sâu initializers thành viên?

Theo như tôi có thể biết, điều này phải làm với điều kiện constexpr 'iveness của hàm tạo mặc định tuple'. is_default_constructible gây ra sự khởi tạo của hàm tạo mặc định. Nó chỉ cần khởi tạo khai báo để xác định xem trình xây dựng này có thể được gọi mà không có lỗi trong ngữ cảnh ngay lập tức hay không. Tuy nhiên, sự khởi tạo của việc khai báo yêu cầu xác định constexpr 'iveness, và điều này gây ra sự khởi tạo của định nghĩa của hàm tạo.

Một hàm thành viên (hoặc constructor) của một lớp mẫu đã được đánh dấu là constexpr chỉ có điều kiện constexpr là: chỉ có các hàm thành viên của những lớp mẫu instantiations sẽ constexpr nơi cơ thể không vi phạm các constexpr hạn chế. Điều này đòi hỏi sự khởi tạo của phần thân của hàm tạo, đối với các hàm tạo để kiểm tra xem các bộ khởi tạo thành viên có được phép bên trong một hàm constexpr hay không.Xem xét:

struct nonconstexpr { nonconstexpr() { std::cout << "runtime\n"; } }; 
struct isconstexpr { constexpr isconstexpr() {} }; 

template<typename T> 
struct wrapper { T t; constexpr wrapper() : t() {} }; 

Khi instantiating ctor mặc định của wrapper, trình biên dịch đã nhanh chóng initializers thành viên nhằm xác định có hay không instantiation này sẽ constexpr.

Trong trường hợp std::tuple, điều này gây ra một nơi nào đó sự khởi tạo của bộ khởi tạo thành viên cố gắng khởi tạo giá trị tham chiếu tuple leaf (thành viên dữ liệu). Đây là một lỗi, và nó không xảy ra trong bối cảnh ngay lập tức của instantiation gốc của constructor mặc định. Vì vậy, nó là một lỗi cứng chứ không phải là một sự thất bại thay thế trong bối cảnh ngay lập tức.

-]

Phần này là không hoàn toàn rõ ràng với tôi vì CWG 1358 về cơ bản làm tất cả instantiations constexpr, dù có hoặc không thực sự đáp ứng các tiêu chí. Và quả thực, gcc 6.0 không thất bại trong việc biên dịch ví dụ sau, trong khi gcc 5.1 và kêu vang 3.7 từ chối nó:

#include <type_traits> 

template<typename T> 
struct foo 
{ 
    T t; 
    constexpr foo() {} // remove `constexpr` to make it compile everywhere 
}; 

int main() 
{ 
    static_assert(std::is_default_constructible<foo<int&>>{}, "!"); 
} 

CWG 1358 cũng cho chúng ta biết lý do tại sao sự khác biệt giữa hai cách tiếp cận - constexpr có điều kiện và constexpr bất chấp vi phạm - là rất quan trọng:

câu hỏi nảy sinh trong các cuộc thảo luận về vấn đề này năm 1581 là liệu phương pháp này - làm cho chuyên môn của một hàm constexpr mẫu hoặc hàm thành viên của một lớp mẫu vẫn constexpr nhưng không thể được áp dụng trong một ngữ cảnh không đổi - là chính xác. Hàm ý là loại lớp học có thể được phân loại theo nghĩa đen nhưng không thể là được khởi tạo tại thời gian biên dịch. Do đó, vấn đề này được trả về trạng thái "đánh giá" để cho phép xem xét thêm câu hỏi này.


Đối libC++, có lỗi #21157, mà đã được giải quyết trên 2014/10/15 và xuất hiện trong các chi nhánh clang3.6. Đối với libstdC++, có vẻ như không phải là một báo cáo lỗi; sự cố đã được khắc phục trong một số combined commit on 2015-06-30 cũng thực hiện N4387 - Improving Pair and Tuple (Revision 3) mà hiện tại dường như không xuất hiện trong bất kỳ chi nhánh gcc5 nào.

+0

Vấn đề là, 'is_default_constructible <>' thường không gây ra thất bại sâu. Trong trường hợp này, nó là. Một cái gì đó để làm với việc thực hiện 'tuple'. – Yakk

+0

@Yakk Ah!Bạn đúng. Nó sẽ chỉ đưa ra một câu trả lời sai ... – dyp

+1

@Yakk Có vẻ như nó phải làm với điều kiện constexpr'iveness oO http://coliru.stacked-crooked.com/a/59356c32a3c764c8 – dyp

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