Chuyển tiếp kiểu trả về trong mã chung
Đối với mã không chung chung, như ví dụ ban đầu bạn đã đưa ra, bạn có thể chọn thủ công để lấy tham chiếu làm loại trả về:
auto const& Example(int const& i)
{
return i;
}
nhưng trong mã chung, bạn muốn có thể chuyển tiếp hoàn hảo một kiểu trả về mà không cần biết bạn đang xử lý một tham chiếu hay một giá trị. decltype(auto)
cung cấp cho bạn khả năng đó:
template<class Fun, class... Args>
decltype(auto) Example(Fun fun, Args&&... args)
{
return fun(std::forward<Args>(args)...);
}
Trì hoãn khấu trừ kiểu trả về trong các mẫu đệ quy
Trong Hỏi & Đáp này vài ngày trước, một đệ quy vô hạn trong quá trình khởi tạo mẫu đã gặp phải khi kiểu trả về của mẫu được chỉ định decltype(iter(Int<i-1>{}))
thay vì decltype(auto)
.
template<int i>
struct Int {};
constexpr auto iter(Int<0>) -> Int<0>;
template<int i>
constexpr auto iter(Int<i>) -> decltype(auto)
{ return iter(Int<i-1>{}); }
int main() { decltype(iter(Int<10>{})) a; }
decltype(auto)
được sử dụng ở đây để trì hoãn việc khấu trừ kiểu trả về sau khi bụi của khởi tạo mẫu đã lắng xuống.
Công dụng khác
Bạn cũng có thể sử dụng decltype(auto)
trong các bối cảnh khác, ví dụ dự thảo Tiêu chuẩn N3936 cũng nêu rõ
7.1.6.4 thông số kỹ thuật tự động [dcl.spec.auto]
1 Kiểu auto
và decltype(auto)
thông số kỹ thuật chỉ định loại giữ chỗ sẽ được thay thế sau này, bằng cách khấu trừ từ trình khởi tạo hoặc bằng cách xác định rõ ràng với kiểu trả về theo sau. Các auto
loại-Speci fi er cũng được sử dụng để biểu thị rằng một lambda là một lambda generic.
2 Loại giữ chỗ có thể xuất hiện cùng với một công cụ khai báo hàm trong dec-specifier-seq, type-specifier-seq, convert-function-id hoặc trailing-return-type, trong bất kỳ ngữ cảnh nào mà trình khai báo đó hợp lệ . Nếu bộ khai báo hàm bao gồm kiểu trả về theo sau (8.3.5), chỉ định kiểu trả về được khai báo của hàm. Nếu loại trả về được khai báo của hàm chứa loại giữ chỗ, loại trả về của hàm được suy ra từ các câu lệnh trả về trong phần thân của hàm, nếu có.
Dự thảo cũng chứa ví dụ về khởi tạo biến này:
int i;
int&& f();
auto x3a = i; // decltype(x3a) is int
decltype(auto) x3d = i; // decltype(x3d) is int
auto x4a = (i); // decltype(x4a) is int
decltype(auto) x4d = (i); // decltype(x4d) is int&
auto x5a = f(); // decltype(x5a) is int
decltype(auto) x5d = f(); // decltype(x5d) is int&&
auto x6a = { 1, 2 }; // decltype(x6a) is std::initializer_list<int>
decltype(auto) x6d = { 1, 2 }; // error, { 1, 2 } is not an expression
auto *x7a = &i; // decltype(x7a) is int*
decltype(auto)*x7d = &i; // error, declared type is not plain decltype(auto)