"Năm 1985, phiên bản đầu tiên của The C++ Programming Language đã được phát hành, mà đã trở thành tài liệu tham khảo dứt khoát cho ngôn ngữ, như đã có chưa một tiêu chuẩn chính thức." wiki C++ History Vì vậy, nó không thay đổi giữa C++ 11 và C++ 14. Tôi có thể giả định (và hãy lấy điều này với một hạt muối) nó thay đổi giữa "chuẩn hóa trước" và tiêu chuẩn hóa. Có lẽ ai đó biết rõ hơn về lịch sử của C++ có thể làm sáng tỏ thêm ở đây.
Đối với những gì thực sự xảy ra:
Đầu tiên chúng ta hãy ra khỏi đường đi đơn giản:
extern g(double);
này không hợp lệ C++. Trong lịch sử, tiếc là C cho phép bỏ sót loại. Trong C++ bạn phải viết extern void g(double)
.
Tiếp theo, hãy bỏ qua những quá tải g(double)
để trả lời câu hỏi đầu tiên của bạn:
template <class T>
void f(T value)
{
g(value);
}
void g(int v);
int main()
{
f(2);
}
Trong C++ có khét tiếng hai giai đoạn tra cứu tên:
- Trong giai đoạn đầu, tại định nghĩa mẫu, tất cả non-dependent names được giải quyết. Không làm như vậy là một lỗi nghiêm trọng;
- Tên phụ thuộc được giải quyết trong giai đoạn hai, tại bản mẫu.
Quy tắc phức tạp hơn một chút, nhưng đó chính là ý chính của nó.
g
phụ thuộc vào thông số mẫu T
để nó chuyển giai đoạn đầu tiên. Điều đó có nghĩa rằng nếu bạn không bao giờ khởi tạo f
, thì mã sẽ biên dịch tốt. Ở giai đoạn thứ hai, f
được khởi tạo với T = int
. g(int)
hiện đang tìm kiếm, nhưng không tìm thấy:
17 : error: call to function 'g' that is neither visible in the template definition nor found by argument-dependent lookup
g(value);
^
24 : note: in instantiation of function template specialization 'f<int>' requested here
f(2);
^
20 : note: 'g' should be declared prior to the call site
void g(int v);
Để cho một cái tên tùy ý g
để vượt qua với màu sắc bay chúng tôi có một vài lựa chọn:
- Khai
g
trước:
void g(int);
template <class T>
void f(T value)
{
g(value);
}
- mang
g
với T
:
template <class T>
void f(T)
{
T::g();
}
struct X {
static void g();
};
int main()
{
X x;
f(x);
}
- Mang
g
với T
qua ADL:
template <class T>
void f(T value)
{
g(value);
}
struct X {};
void g(X);
int main()
{
X x;
f(x);
}
Những dĩ nhiên thay đổi ngữ nghĩa của chương trình. Họ có nghĩa là để minh họa những gì bạn có thể và không thể có trong một mẫu.
Đối với lý do tại sao không ADL tìm g(int)
, nhưng thấy g(X)
:
§ 3.4.2 Argument-dependent name lookup [basic.lookup.argdep]
For each argument type T in the function call, there is a set of zero or more associated namespaces and a set of zero or more associated classes to be considered [...]:
If T is a fundamental type, its associated sets of namespaces and classes are both empty.
If T is a class type (including unions), its associated classes are: the class itself; the class of which it is a member, if any; and its direct and indirect base classes. Its associated namespaces are the namespaces of which its associated classes are members. [...]
Và cuối cùng chúng tôi nhận được lý do tại sao extern void g(double);
bên trong chính là không tìm thấy: trước hết chúng tôi cho thấy rằng g(fundamental_type)
được tìm thấy iff nó được khai báo trước định nghĩa f
. Vì vậy, hãy làm cho nó void g(X)
bên trong main
. ADL có tìm thấy nó không?
template <class T>
void f(T value)
{
g(value);
}
struct X{};
int main()
{
X x;
void g(X);
f(x);
}
số Bởi vì nó không nằm trong không gian tên giống như X
(ví dụ: namespace toàn cục) ADL không thể tìm thấy nó.
Proof rằng g
không có trong thế giới
int main()
{
void g(X);
X x;
g(x); // OK
::g(x); // ERROR
}
34 : error: no member named 'g' in the global namespace; did you mean simply 'g'?
"Năm 1985, phiên bản đầu tiên của The C++ Programming Language đã được phát hành, mà đã trở thành tài liệu tham khảo dứt khoát cho ngôn ngữ, như ** đã có không một tiêu chuẩn chính thức **. " [wiki] (https://en.wikipedia.org/wiki/C%2B%2B#History) Vì vậy, nó không thay đổi giữa 'C++ 11' và' C++ 14'. Nó thay đổi giữa "chuẩn hóa trước" và tiêu chuẩn hóa. – bolov
Kiểm tra 14.6.4.1 [temp.point] cho các quy tắc – AndyG
cũng tìm kiếm tra cứu tên hai giai đoạn – bolov