2016-10-07 15 views
9

Dưới đây là một ví dụ nhỏ gọn của một nghị quyết tình trạng quá tải rất lạ từ một mẫu bối cảnh:C++ độ phân giải mẫu quá tải gọi từ ứng cử viên chọn mẫu chức năng tuyên bố sau khi mẫu instantiation

#include <iostream> 

// Types // 
struct I { int v; }; 

template <class T> 
struct D { T t; }; 

// Functions // 

// Overload 1 
template <class T> 
I f(T) { return {1}; } 

// Template indirection that calls f(T) 
template <class T> 
I g(D<T>) { return f(T{}); } 

// Non template indirection that calls f(T) 
I h(D<I>) { return f(I{}); } 

int main() { 
    std::cout 
     << f(I{}).v  // f(I{}) overload called directly 
     << "\n"   // => overload 1 called 
     << h(D<I>{}).v // f(I{}) called though non-template 
     << "\n"   // => overload 1 called 
     << g(D<I>{}).v // f(I{}) called though template 
     << "\n";  // => overload 2 actually called ??? 
} 

// Overload 2 
// Should not be reachable as declared after all f(...) calls. 
// If was a candidate, would be chosen over 1. 
I f(I) { return {2}; } 

này dường như có liên quan đến ADL vì nếu I được đặt trong một không gian tên "quá tải 1" luôn được gọi.

Tôi biết rằng ADL được thực hiện như thể cuộc gọi được thực hiện từ điểm khởi tạo mẫu (main).

Đối với tên phụ thuộc được sử dụng trong định nghĩa mẫu, tra cứu được hoãn cho đến khi đối số mẫu được biết, tại thời điểm đó ADL kiểm tra khai báo hàm với liên kết bên ngoài (cho đến C++ 11). ngữ cảnh định nghĩa cũng như trong bối cảnh instantiation mẫu, trong khi tra cứu không phải ADL chỉ kiểm tra các khai báo hàm với liên kết bên ngoài (cho đến C++ 11) được hiển thị từ ngữ cảnh định nghĩa mẫu. http://en.cppreference.com/w/cpp/language/unqualified_lookup#Template_definition

Nhưng tại đây "Quá tải 2" được khai báo SAU main! main là điểm instanciation của gf, tôi giả định chỉ chức năng được khai báo trướcmain sẽ là ứng cử viên quá tải.

Lưu ý rằng hành vi này có liên quan đến g là mẫu dưới dạng hàm mẫu không tương thích của h (g) gọi là "Quá tải 1".

Làm cách nào để "quá tải 2" - được tuyên bố sau main - bao giờ được gọi?

Hành vi này đã được sao chép bằng tiếng kêu + (3.8.1) và g ++ (6.2.1).

Trả lời

5

[temp.dep.candidate]/1:

Nếu cuộc gọi sẽ được vô hình thành hoặc sẽ tìm thấy một trận đấu tốt hơn đã tra cứu trong không gian tên có liên quan xem xét tất cả các chức năng tờ khai với mối liên hệ bên ngoài giới thiệu trong những không gian tên trong tất cả đơn vị dịch thuật, không chỉ xem xét những tuyên bố đó được tìm thấy trong định nghĩa mẫu và bối cảnh tức thì mẫu, sau đó chương trình có hành vi không xác định.

Hơn nữa, [temp.point]/6, tôi nhấn mạnh:

Một chuyên môn hoá cho một hàm mẫu [...] có thể có nhiều điểm của sự khởi tạo trong một đơn vị dịch thuật, và thêm vào các điểm instantiation được mô tả ở trên, cho bất kỳ chuyên ngành nào như vậy có điểm khởi tạo trong đơn vị dịch , phần cuối của đơn vị dịch cũng được coi là một điểm của instantiation. [...] Nếu có hai điểm khác nhau về cách diễn đạt , hãy cung cấp cho chuyên môn mẫu ý nghĩa khác nhau theo quy tắc một định nghĩa ([basic.def.odr]), chương trình bị hỏng, không yêu cầu chẩn đoán .

Hành vi của chương trình của bạn chưa được xác định.

+0

Điều đó bổ sung thêm một hòn đá khác chống lại việc thêm quá tải vào không gian tên của thư viện. Việc bổ sung này có thể dẫn đến hành vi không xác định nếu quá tải này có thể được chọn trong mã thư viện. Biết quy tắc, không hợp lý. –

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