5

Với chức năng mẫu sau:Tại sao trình biên dịch không chọn quá tải hàm mẫu của tôi trong ví dụ sau?

#include <vector> 
#include <utility> 

struct Base { }; 
struct Derived : Base { }; 

// #1 
template <typename T1, typename T2> 
void f(const T1& a, const T2& b) 
{ 
}; 

// #2 
template <typename T1, typename T2> 
void f(const std::vector<std::pair<T1, T2> >& v, Base* p) 
{ 
}; 

Tại sao nó rằng đoạn mã sau luôn gọi quá tải # 1 thay vì tình trạng quá tải # 2?

int main() 
{ 
    std::vector<std::pair<int, int> > v; 
    Derived derived; 

    f(100, 200); // clearly calls overload #1 
    f(v, &derived);   // always calls overload #1 

    return 0; 
} 

Cho rằng tham số thứ hai của f là một loại có nguồn gốc của Base, tôi đã hy vọng rằng trình biên dịch sẽ chọn quá tải # 2 vì nó là một trận đấu tốt hơn so với loại chung trong tình trạng quá tải # 1.

Có bất kỳ kỹ thuật nào mà tôi có thể sử dụng để viết lại các chức năng này để người dùng có thể viết mã như được hiển thị trong chức năng main (tức là, tận dụng trình biên dịch-khấu trừ các loại đối số) không?

+0

Mặc dù nó không liên quan đến câu hỏi chính, vẫn: 1. 'int main()', vui lòng. 2. Định nghĩa hàm mẫu của bạn được theo sau bởi các khai báo trống ';'. Điều này là bất hợp pháp trong C++. – AnT

Trả lời

12

Bạn có thể làm điều này:

f(v, static_cast<Base*>(&derived)); 

Hoặc sử dụng SFINAE để loại bỏ đầu tiên hoạt động như một ứng cử viên lựa chọn:

// Install boost library and add these headers: 
#include <boost/utility/enable_if.hpp> 
#include <boost/type_traits.hpp> 

// #1 - change it to look like this (note the keyword void changed positions) 
template <typename T1, typename T2> 
typename boost::disable_if< 
    typename boost::is_convertible<T2, Base*>, void>::type 
f(const T1& a, const T2& b) 
{ 
}; 

// #2 - this one can stay the same 
template <typename T1, typename T2> 
void f(const std::vector<std::pair<T1, T2> >& v, Base* p) 
{ 
}; 
+0

Tăng tốc để giải cứu! Rất thông minh! –

+0

Dang Tôi vừa thêm cái này. :) – GManNickG

+0

Điều đáng buồn duy nhất là nó không thể đọc được nhiều ...1 anyway, giải thích là tốt, đề xuất một giải pháp thậm chí còn tốt hơn :) –

8

Cho rằng tham số thứ hai của f là một loại có nguồn gốc của cơ sở

Đó là chuyển đổi thành như vậy, nhưng nó là một nguồn gốc *. Hàm mẫu đầu tiên không yêu cầu chuyển đổi, và hàm thứ hai yêu cầu một, do đó nó chọn đầu tiên.

này chọn thứ hai:

f(v, static_cast<Base*>(&derived)); 

Trên một mặt lưu ý, main trả về một int.

+0

Cảm ơn bạn đã giải thích. Tôi đã gỡ bỏ giá trị trả về từ chính vì nó không cần thiết trong ví dụ. –

+0

Vâng chính có một 'trở về 0' ngầm định, vì vậy bạn có thể để lại int anyway :) Và đó là một nhân vật ngắn hơn! : P – GManNickG

+3

Cần thiết hay không, ngôn ngữ C++ _requires_ 'main' được khai báo với kiểu trả về 'int'. – AnT

1

Bên cạnh các chủ đề rõ ràng về Koenig Lookup được thực hiện nhiều hơn hoặc ít hơn bởi các trình biên dịch (đặc biệt là các trình biên dịch cũ), có một vài cạm bẫy liên quan đến template specialization.

Chuyên môn yêu cầu các loại đối sánh chính xác (không chắc chắn cách std định nghĩa điều này, nhưng từ kinh nghiệm của tôi [gcc, msvc] một lớp dẫn xuất sẽ không được khớp). Nếu bạn thêm một dàn diễn viên xấu xí đến cơ sở *, nó sẽ làm việc như bạn có ý định, tùy chọn thêm chuyên môn khác cho nguồn gốc ...

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