2017-12-17 25 views
5

Hãy nói rằng chúng tôi có một lớp học như thế này với một hướng dẫn khấu trừ do người dùng định nghĩa:người dùng định nghĩa vs mẫu khấu trừ tự động hướng dẫn ưu tiên

template<typename T, typename... Args> 
struct Foo 
{ 
    Foo(Args&&...) { std::cout << "just Args: " << __PRETTY_FUNCTION__ << std::endl; } 
    Foo(Args&&..., T&&) { std::cout << "Args and T: " << __PRETTY_FUNCTION__ << std::endl; } 
}; 

template<typename... Args> 
Foo(Args&&...) -> Foo<Void, Args...>; 

Bây giờ chúng ta hãy cố gắng tạo ra một thể hiện của lớp này: Foo foo { 10 };. Điều gì sẽ được các đối số mẫu suy luận và những gì constructor sẽ được gọi là?

Sau khi một số thử nghiệm hóa ra nó phụ thuộc vào trình biên dịch. Cụ thể, gcc 7 và kêu vang 6 (từ thân cây) dường như để lựa chọn hướng dẫn tự động, instantiating T với intArgs với một gói sản phẩm nào, vì thế mà đầu ra là

Args and T: Foo<T, Args>::Foo(Args&& ..., T&&) [with T = int; Args = {}] 

kêu vang 5, mặt khác, chọn hướng dẫn do người dùng xác định:

just Args: Foo<Void, int>::Foo(Args &&...) [T = Void, Args = <int>] 

Lựa chọn nào là đúng và cách người dùng có thể sử dụng hướng dẫn khấu trừ do người dùng xác định trong trường hợp này?

Ví dụ đầy đủ có sẵn trên wandbox.

Trả lời

3

Chúng ta hãy đi từ nguyên tắc đầu tiên. Đang cố gắng để suy ra từ Foo{10} liên quan đến việc thực hiện Nghị quyết tình trạng quá tải vào nhóm này:

template <typename T, typename... Args> 
Foo<T, Args...> __f(Args&&...); // ctor #1 

template <typename T, typename... Args> 
Foo<T, Args...> __f(Args&&..., T&&); // ctor #2 

template <typename... Args> 
Foo<Void, Args...> __f(Args&&...); // deduction guide 

Trong chức năng tổng hợp từ các nhà xây dựng đầu tiên, T là một bối cảnh phi suy luận. Trong hàm tổng hợp từ hàm tạo thứ hai, Args là một ngữ cảnh không được suy luận. Vì vậy, không phải là khả thi. Hướng dẫn khấu trừ là khả thi, do đó, nó là tầm thường các ứng cử viên khả thi tốt nhất, vì vậy chúng tôi kết thúc với một Foo<Void, int>.

Khi đã ở đó, chúng tôi thực hiện lại độ phân giải quá tải để chọn một hàm tạo. Điều này là đơn giản hơn, cái đầu tiên là khả thi và cái thứ hai là không, vì vậy nó nên được gọi.

Bất kỳ hành vi nào khác là lỗi trình biên dịch (nộp 83447).

+1

Tại sao 'Args' là một ngữ cảnh không suy luận trong hàm tổng hợp từ ctor # 2? Có vẻ như nó hoàn toàn có thể suy luận được: một gói rỗng trong trường hợp cụ thể này. – 0xd34df00d

+1

@ 0xd34f00d http://eel.is/c++draft/temp#deduct.type-5.7 – Barry

+0

Phải, tôi đã đưa ra một ví dụ đơn giản gần với những gì bạn đã hiển thị trong báo cáo lỗi và nó được biên dịch tốt với tất cả các gcc của tôi đã cố gắng và cả hai clang 5 và 6, vì vậy tôi giả định nó là chính xác. Các liên kết bạn đã chứng minh nó không phải! Thật thú vị, clang <4 từ chối mã. Bây giờ, để làm cho mã hoạt động với các trình biên dịch hiện có, tôi đã thêm một tham số thẻ giả vào ctor thứ hai, vì ctor đó là một chi tiết triển khai và không nên được gọi bởi người dùng lớp. Cảm ơn rất nhiều! – 0xd34df00d

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