6

Giả nơi nào đó trong mã của tôi là một hàm foo với một tham số tài liệu tham khảo phổ quát, mà tôi không thể thay đổi:độ phân giải C++ quá tải với chức năng tham khảo phổ mẫu mà không thể thay đổi

template<typename T> 
auto foo(T&& t) { std::cout<<"general version"<<std::endl; } 

Bây giờ tôi muốn quá tải foo cho một lớp nhất định A và đảm bảo rằng đối với bất kỳ loại vòng loại và tham chiếu nào của số A, quá tải được gọi. Đối với tôi điều này có thể brute-forcely cung cấp một tình trạng quá tải cho tất cả các bằng cấp có thể (bỏ qua volatile cho bây giờ):

auto foo(A & a) { std::cout<<"A&"<<std::endl; } 
auto foo(A const& a) { std::cout<<"A const&"<<std::endl; } 
auto foo(A && a) { std::cout<<"A &&"<<std::endl; } 
auto foo(A const&& a) { std::cout<<"A const&&"<<std::endl; } 

Demo. Tuy nhiên, điều này quy mô rất kém để biết thêm thông số.

Ngoài ra, tôi có thể vượt qua bởi giá trị, mà dường như để nắm bắt cũng như tất cả các trường hợp theo thời gian:

auto foo(A a) { std::cout<<"A"<<std::endl; } 

Demo. Bây giờ, tuy nhiên đối tượng lớn cần phải được sao chép (- ít nhất là về nguyên tắc).

Có cách nào thanh lịch xung quanh những vấn đề này không?

Hãy nhớ rằng tôi không thể thay đổi chức năng tham chiếu phổ quát, vì vậy SFINAE và những thứ tương tự không có khả năng.

+0

Viết hàm bao hàm để chuyển tiếp các đối số đến đúng chức năng và sử dụng giải pháp đó thay vì hợp lý cho bạn? – TartanLlama

+0

AFAIK trình biên dịch luôn tìm kiếm các tùy chọn cụ thể nhất. Điều gì xảy ra nếu bạn thêm một enable_if > vào "quá tải"? –

+1

@ TartanLlama: không thực sự. Trong mã, hàm tương ứng là 'operator &&' (tôi chỉ lấy 'foo' làm ví dụ đơn giản). Đó là một thư viện và đó là quá sai lầm. – davidhigh

Trả lời

7

Thành thật mà nói, tôi nghĩ bạn không may mắn ở đây. Các cách tiếp cận điển hình đều thất bại. Bạn có thể làm ...

SFINAE?

template <typename T> auto foo(T&&); 
template <typename T, 
      typename = only_if_is<T, A>> 
auto foo(T&&); 

foo(A{}); // error: ambiguous 

Viết một lớp học có tham chiếu l-hoặc-rvalue?

template <typename T> lref_or_ref { ... }; 

template <typename T> auto foo(T&&); 
auto foo(lref_or_ref<A>); 

foo(A{}); // calls general, it's a better match 

Điều tốt nhất bạn có thể làm là giới thiệu một chức năng chuyển tiếp sử dụng một tính năng chọn:

template <int I> struct chooser : chooser<I - 1> { }; 
template <> struct chooser<0> { }; 

template <typename T> 
auto bar(T&& t, chooser<0>) { 
    // worst-option, general case 
    foo(std::forward<T>(t)); 
} 

template <typename T, 
      typename = only_if_is<T, A>> 
auto bar(T&& t, chooser<1>) { 
    // A-specific 
} 

template <typename T> 
auto bar(T&& t) { 
    bar(std::forward<T>(t), chooser<20>{}); 
} 

Nhưng bạn đề cập in a comment rằng điều này không làm việc cho bạn một trong hai. Vì vậy, tôi đoán, một lựa chọn của bạn là: viết một đề xuất cho ủy ban tiêu chuẩn!


Về mặt kỹ thuật, có hy vọng! Nếu các khái niệm được chấp nhận (điểm tốt, TartanLlama!):

template <typename T> 
    requires IsForwardRefTo<T, A> 
auto foo(T&& t) { 
    // since this is more constrained than the generic forwarding reference 
    // this one should be preferred for foo(A{}) 
} 
+0

Có thể nhận được ít nhất các giá trị bằng 'template auto foo (T & t);', nhưng dường như không có cách nào để làm điều đó cho giá trị. Trừ khi bạn sử dụng các khái niệm, đó là (nơi bạn có thể xác định tham số tham chiếu rvalue suy luận thuần túy), nhưng sau đó bạn có thể sử dụng giải pháp dễ dàng hơn để có được cả hai thông qua một ref chuyển tiếp bị hạn chế. – dyp

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