T có phải là một loại hoàn chỉnh được sử dụng trong `std :: decval <T>` không?


11

Xem xét ví dụ này (đến từ đây ):

#include <type_traits>
#include <iostream>
template <typename U>
struct A {
};

struct B {
   template <typename F = int>
   A<F> f() { return A<F>{}; }

   using default_return_type = decltype(std::declval<B>().f());
};

int main()
{
    B::default_return_type x{};
    std::cout << std::is_same< B::default_return_type, A<int>>::value;
}

biên dịch không có lỗi trên gcc9.2 nhưng gcc7.2 và clang 10.0.0 phàn nàn về việc Bkhông hoàn thành. Lỗi Clangs là:

prog.cc:11:58: error: member access into incomplete type 'B'
   using default_return_type = decltype(std::declval<B>().f());
                                                         ^
prog.cc:7:8: note: definition of 'B' is not complete until the closing '}'
struct B {
       ^
prog.cc:16:8: error: no type named 'default_return_type' in 'B'
    B::default_return_type x{};
    ~~~^
prog.cc:17:35: error: no member named 'default_return_type' in 'B'
    std::cout << std::is_same< B::default_return_type, A<int>>::value;
                               ~~~^

1
Tiêu đề câu hỏi không xuất hiện để phù hợp với lỗi? Đối với tôi, có vẻ như GCC phàn nàn về .f(). Điều đó có ý nghĩa; loại không đầy đủ Bkhông có thành viên f.
MSalters

@MSalters tôi cũng nghĩ như vậy, nhưng vấn đề thực sự ở đây là gì? Tôi sẽ giả sử rằng một khi bạn có một ví dụ từ std::declvalnó thì không còn quan trọng nữa nếu kiểu đó đã hoàn thành hay chưa (và tôi đoán là tôi đã sai với điều đó)
idclev 463035818

[expr.ref] / 2 (C ++ 11) nói về quyền truy cập của thành viên lớp: "Đối với tùy chọn đầu tiên (dấu chấm), biểu thức đầu tiên sẽ có loại lớp hoàn chỉnh" . Và Bkhông hoàn thành cũng không được coi là hoàn thành alias-declaration.
Luật sư ngôn ngữ


1
@L LanguageLawyer ok thì tôi đồng ý rằng cách giải thích của tôi đã bị tắt và có vẻ như đã có gì đó thay đổi kể từ c ++ 11, điều này làm cho các điều trên ok trong các tiêu chuẩn mới hơn nhưng không phải trong c ++ 11. Bạn có phiền khi viết một câu trả lời?
idclev 463035818

Câu trả lời:


9

Nguồn của lỗi không phải là std::declval, nhưng truy cập thành viên lớp không đầy đủ.

Cho đến khi độ phân giải của CWG1836 được sáp nhập 2,5 năm trước, tiêu chuẩn yêu cầu lớp phải được hoàn thành trong một biểu thức truy cập thành viên lớp ( E1.E2).
[expr.ref] / 2 trong C ++ 11 :

Đối với tùy chọn đầu tiên (dấu chấm), biểu thức đầu tiên sẽ có kiểu lớp hoàn chỉnh.

[expr.ref] / 2 trong C ++ 17 :

Đối với tùy chọn đầu tiên (dấu chấm), biểu thức đầu tiên sẽ là một giá trị có loại lớp hoàn chỉnh.

Và một lớp không được coi là hoàn thành trong alias-declarationchính nó member-specification.
[class.mem] / 6 trong C ++ 17 :

Một lớp được coi là một loại đối tượng được xác định hoàn toàn ([basic.types]) (hoặc loại hoàn chỉnh) khi đóng }trình xác định lớp . Trong đặc tả thành viên lớp , lớp được coi là hoàn chỉnh trong các thân hàm, đối số mặc định, s-specifier-specifier và bộ khởi tạo thành viên mặc định (bao gồm cả những thứ đó trong các lớp lồng nhau). Mặt khác, nó được coi là không đầy đủ trong đặc tả thành viên lớp của chính nó .


8

Từ [tuyên bố] :

Lưu ý: Tham số mẫu Tcủa declvalcó thể là một loại không đầy đủ.

Từ ngữ này đã có mặt từ C ++ 11 (vì vậy các trình biên dịch không thể tuân thủ một tiêu chuẩn trước đó)


tuyệt vời, đó là những gì tôi đã hy vọng. Có vẻ như gcc đã sửa nó, tiếng kêu chưa (chưa)
idclev 463035818

@ trước đây là Unknown_463035818: Suy nghĩ đầu tiên của tôi là đó Thoàn toàn là một loại hoàn chỉnh. Vui mừng tôi đã kiểm tra tiêu chuẩn.
AndyG
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.