xem xét mã này:
template<class T> using identity = T;
template<class T> void foo(identity<T>&&) { } //#1
template<class T> void foo(T&&) { } //#2
int main()
{
int i{};
foo(i);
}
Cả GCC và Clang từ chối nó vì #2
là một định nghĩa mới của #1
. Nếu chúng thực sự là cùng một mẫu, chúng tôi có thể mong đợi #1
hoạt động theo cách chính xác giống như #2
, có nghĩa là identity<T>&&
sẽ hoạt động như một tham chiếu chuyển tiếp. Theo logic này, chúng ta không biết cái nào là đúng, nhưng GCC ít nhất là nhất quán.
Điều này cũng phù hợp với ví dụ rất giống với tiêu chuẩn tại [14.5.7p2].
Chúng tôi cũng nên xem xét cách khấu trừ đối số mẫu có thể hoạt động trong trường hợp này. Nếu identity
là một mẫu lớp, biểu mẫu của nó có thể được so khớp với loại đối số hàm mà không nhìn vào định nghĩa của nó, cho phép trình biên dịch suy ra đối số mẫu cho T
. Tuy nhiên, ở đây chúng tôi có một mẫu bí danh; Không thể khấu trừ T
vào int
hoặc int&
hoặc bất kỳ điều gì khác trừ khi identity<T>
được thay thế bằng T
. Nếu không, chúng ta đang đối đầu với cái gì? Sau khi thay thế xong, tham số hàm trở thành tham chiếu chuyển tiếp.
Tất cả những điều trên đều hỗ trợ ý tưởng identity<T>&&
(và identity<T&&>
) được coi là tương đương với tham chiếu chuyển tiếp.
Tuy nhiên, có vẻ như có nhiều điều hơn đến việc thay thế ngay mẫu bí danh-id bằng loại id tương ứng. Đoạn [14.5.7p3] cho biết:
Tuy nhiên, nếu id mẫu phụ thuộc, đối số mẫu tiếp theo thay thế vẫn áp dụng cho id mẫu. [Ví dụ:
template<typename...> using void_t = void;
template<typename T> void_t<typename T::foo> f();
f<int>(); // error, int does not have a nested type foo
-end dụ]
này có thể dường như không có nhiều việc phải làm với ví dụ của bạn, nhưng nó thực sự chỉ ra rằng hình thức ban đầu của mẫu-id vẫn đưa vào trong một số trường hợp, độc lập với loại id thay thế. Tôi đoán điều này mở ra khả năng rằng sau này tất cả mọi thứ có thể thực sự không được coi là một tham chiếu chuyển tiếp identity<T>&&
.
Khu vực này có vẻ không được xác định trong tiêu chuẩn. Điều này cho thấy trong số các vấn đề mở đối phó với các vấn đề tương tự, tất cả trong cùng một danh mục theo ý kiến của tôi: trong trường hợp nào thì dạng mẫu ban đầu của mẫu-id được tính đến khi khởi tạo, mặc dù nó được thay thế bằng tương ứng với loại-id ngay lập tức khi gặp phải. Xem các vấn đề 1980, 2021 và 2025. Ngay cả các vấn đề 1430 và 1554 có thể được xem là xử lý các vấn đề tương tự.
Đặc biệt, issue 1980 chứa các ví dụ sau:
template<typename T, typename U> using X = T;
template<typename T> X<void, typename T::type> f();
template<typename T> X<void, typename T::other> f();
với lưu ý:
CWG cảm thấy rằng hai tờ khai này không nên tương đương.
(CWG - Tổ công tác Core)
Một dòng tương tự như lập luận có thể áp dụng đối với ví dụ của bạn, làm cho identity<T>&&
không tương đương với một tham chiếu chuyển tiếp. Điều này thậm chí có thể có giá trị thực tế, như một cách đơn giản để tránh tham lam của tham chiếu chuyển tiếp khi tất cả những gì bạn muốn là một tham chiếu rvalue cho một suy luận T.
Vì vậy, tôi nghĩ bạn đã nêu ra một vấn đề rất thú vị. Ví dụ của bạn có thể đáng để thêm làm ghi chú cho số issue 1980, để đảm bảo ví dụ này được tính đến khi soạn thảo giải pháp.
Theo ý kiến của tôi, câu trả lời cho câu hỏi của bạn là, bây giờ, một sự vang dội "ai biết?".
Cập nhật: Trong những ý kiến đến đầu kia, liên quan, question, Piotr S. chỉ ra issue 1700, được đóng như "không phải là một khiếm khuyết". Nó đề cập đến trường hợp rất giống nhau được mô tả trong câu hỏi đó, và chứa các lý do sau đây:
Bởi vì các loại của các thông số chức năng là như nhau, bất kể bằng văn bản trực tiếp hoặc thông qua một mẫu bí danh, khấu trừ phải được xử lý theo cùng một cách trong cả hai trường hợp.
Tôi nghĩ rằng nó cũng áp dụng cho các trường hợp được thảo luận ở đây và giải quyết vấn đề ngay bây giờ: tất cả các biểu mẫu này sẽ được coi là tương đương với tham chiếu chuyển tiếp. Nó sẽ rất thú vị để xem nếu điều này được thay đổi gián tiếp bởi các nghị quyết cho các vấn đề mở khác, nhưng họ chủ yếu là đối phó với thất bại thay thế hơn là khấu trừ của chính nó, vì vậy tôi đoán một hiệu ứng gián tiếp là khá khó xảy ra.)
Tất cả các tham chiếu chuẩn là bản nháp làm việc hiện tại, N4431, bản nháp thứ hai sau C++ 14 cuối cùng.
Lưu ý rằng trích dẫn từ [14.5.7p3] là một bổ sung gần đây, được bao gồm ngay sau phiên bản C++ 14 cuối cùng với độ phân giải DR1558. Tôi nghĩ chúng ta có thể mong đợi những bổ sung thêm trong lĩnh vực này khi các vấn đề khác được giải quyết theo cách này hay cách khác.
Cho đến lúc đó, có thể đáng để đặt câu hỏi này trong nhóm ISO C++ Standard - Discussion; nên mang nó đến sự chú ý của đúng người.
Điều thú vị, 'danh tính' có vẻ hoạt động trong cả GCC và Clang ([demo] (http://melpon.org/wandbox/permlink/r1YH40UcY8lwouQ4)) được coi là tham chiếu chuyển tiếp –
Đó có thể là do 'T && '* là * của định dạng được chỉ định cho tham chiếu chuyển tiếp. – Angew
@Angew Có, nhưng dưới dạng tham số hàm, không phải là đối số mẫu trong mẫu-id. – bogdan