2012-06-21 42 views
10

Quy trình so sánh các loại chuyên môn template là gì? Tiêu chuẩn không được nêu chi tiết về điểm này (hoặc tôi thiếu địa điểm phù hợp).
Câu hỏi của tôi KHÔNG GÌ với quyết định sử dụng chuyên môn nào trong quá trình khởi tạo. Xin vui lòng, không bình luận về điều đó. Câu hỏi đặt ra là so sánh các chuyên môn với nhau để quyết định xem chuyên môn cụ thể đã được xác định hay chưa.Tại sao trình biên dịch không đưa ra lỗi trong khi xác định các chuyên môn mẫu tương tự?

xem xét mẫu mã này:

template <class x1, class x2> 
struct CoreTemplate { }; 

template <class x1, class x2> 
struct CoreTemplate<x1*, x2*> { int spec; CoreTemplate() { spec = 1; } }; 

template <class x1, class x2> 
struct CoreTemplate<x2*, x1*> { int spec; CoreTemplate() { spec = 2; } }; 

int main(int argc, char* argv[]) 
{ 
    CoreTemplate<int*, int*> qq; 
    printf("var=%d.\r\n", qq.spec); 
} 

Khi tôi cố gắng để biên dịch mã này với MSVC, tôi nhận được một lỗi cho các nỗ lực instantiation bên trong main chức năng:

cpptest1.cxx (15): lỗi C2752: 'CoreTemplate<x1,x2>': nhiều chuyên môn từng phần khớp với danh sách đối số mẫu

Đối với tôi nó sẽ là hợp lý hơn để phát hành một lỗi cho một nỗ lực để khai báo chuyên môn mẫu giống hệt nhau. Tôi không thấy bất kỳ sự khác biệt nào giữa các chuyên ngành ở trên.

Vì vậy, không ai biết quy tắc so sánh các chuyên môn về mẫu? Các bài báo, liên kết, sách, vv cũng sẽ giúp ích.

+0

Câu hỏi hay. Đã chỉnh sửa với tiêu đề và thẻ thích hợp. – iammilind

+0

FYI: clang 3.1 có vẻ có hành vi tương tự. –

Trả lời

5

Tiêu chuẩn cụ thể trong việc nói rằng điều này chỉ xảy ra khi bạn cố gắng tạo mẫu (§14.5.4.1/1):

Khi một lớp mẫu được sử dụng trong một bối cảnh mà đòi hỏi một instantiation của lớp, nó là cần thiết để xác định xem instantiation là được tạo ra bằng cách sử dụng mẫu tiểu học hoặc một trong các chuyên môn từng phần. [nhấn mạnh thêm]

Thật không may, phần còn lại của câu hỏi của bạn không thể trả lời được mà không bàn về cách quyết định nên sử dụng chuyên môn nào trong quá trình khởi tạo. Đây là văn bản từ tiêu chuẩn (tiếp tục từ đoạn trích ở trên):

này được thực hiện bằng cách kết hợp các đối số mẫu của lớp mẫu chuyên môn với danh sách mẫu tranh luận của các chuyên ngành phần.

  • Nếu tìm thấy chính xác một chuyên môn phù hợp, thì việc tạo bản đồ được tạo từ chuyên môn đó.
  • Nếu tìm thấy nhiều hơn một chuyên môn phù hợp, các quy tắc đặt hàng một phần (14.5.4.2) được sử dụng để xác định liệu một trong các chuyên môn có chuyên môn hơn các chuyên ngành khác hay không. Nếu không có chuyên môn nào chuyên biệt hơn tất cả các chuyên ngành phù hợp khác, thì việc sử dụng mẫu lớp không rõ ràng và chương trình không đúng định dạng.

Vì vậy, nó thậm chí không bao giờ cố gắng so sánh các mẫu trực tiếp với nhau. Thay vào đó, nó cố gắng tìm một chuyên môn phù hợp với các đối số đã cho. Nếu có nhiều hơn một kết quả phù hợp, nó sẽ cố gắng chọn một đối tượng đặc biệt nhất dựa trên các quy tắc đặt hàng một phần. Nếu không phải là chuyên môn hơn so với khác, sau đó instantiation là mơ hồ, và biên dịch không thành công.

Bây giờ, chắc chắn là không có chuyên môn nào có thể được sử dụng, vì sẽ luôn có sự mơ hồ - nếu một trong hai kết quả phù hợp, thì kết quả khác rõ ràng là phù hợp. Chỉ đơn giản là không có yêu cầu cho trình biên dịch để phát hiện hoặc chẩn đoán rằng mặc dù. Trong trường hợp chính xác này (về cơ bản các chuyên ngành giống hệt nhau) có thể dễ dàng, nhưng gần như chắc chắn các trường hợp khác sẽ khó khăn hơn nhiều, vì vậy (rõ ràng) ủy ban đã quyết định trình biên dịch thậm chí không phải thử.

+2

Tôi nghĩ rằng tất cả điều này đi xuống đến một quy tắc định nghĩa. Chỉ có một định nghĩa của một mẫu, và một chuyên môn hóa một phần là một khuôn mẫu. Vì vậy, chúng tôi thực sự còn lại với câu hỏi liệu hai chuyên môn có được coi là cùng một khuôn mẫu hay không và tôi không thể tìm thấy bất kỳ điều gì trong tiêu chuẩn xác định rõ ràng điều đó. Bằng cách nghiên cứu hành vi của g ++, nó xem xét hai chuyên ngành là cùng một khuôn mẫu nếu các danh sách đối số khuôn mẫu giống nhau, trong khi bỏ qua các tên cụ thể. –

+0

Cảm ơn nhận xét hợp lý. –

+0

Điều này không hoàn toàn đúng. Trình biên dịch cần so sánh các danh sách đối số chuyên môn hóa một phần. Hãy suy nghĩ về các định nghĩa ngoài dòng của các hàm thành viên của các chuyên môn từng phần. Trình biên dịch cần liên kết định nghĩa với một trong số chúng. –

0

Đối với tôi sẽ là hợp lý hơn khi phát hành lỗi khi cố gắng tuyên bố các chuyên môn mẫu giống nhau.

Điều đó sẽ không xảy ra, bởi vì CoreTemplate<int*, double*>CoreTemplate<double*, int*> sẽ tạo các loại khác nhau.

Dưới đây là dự đoán của tôi:
trình biên dịch có thể không làm thêm sanity/chung cảm giác kiểm tra cho cơ quan template.
Khi bạn khởi tạo template, lúc đó trình biên dịch tìm kiếm loại đối sánh và chọn loại tốt nhất. Nếu nó không khớp với chỉ một, thì nó sẽ cung cấp lỗi trình biên dịch cho không khớp hoặc nhiều kết hợp.

Ví dụ:

template<typename T> 
void foo() 
{ 
    T::x(); 
} 

int main() 
{ 
} 

sẽ biên dịch tốt, mặc dù chúng ta biết rằng trong toàn bộ chương trình C++ có không phải là một tên hàm đơn x(). Trình biên dịch sẽ chỉ cung cấp lỗi khi bạn thử khởi tạo foo<T>.

Ngoài ra, nếu bạn xoay ví dụ của mình một chút bằng cách đặt main() giữa hai chuyên ngành, nó sẽ compile perfectly fine.

+0

Không thực sự. Nếu tôi đặt chuyên môn thứ hai vào mã hai lần, tôi ngay lập tức nhận được: 'cpptest1.cxx (14): lỗi C2953: 'CoreTemplate ': mẫu lớp đã được định nghĩa'. Bên cạnh đó ngôn ngữ cho phép thực hiện các phương pháp chuyên môn bên ngoài định nghĩa. Từ trình biên dịch tiêu đề phương thức phải hiểu những gì chuyên môn hóa phương pháp này thuộc về. –

+0

Tuy nhiên, sự thay đổi là gian lận, bản chất của C (và C++) là chỉ tra cứu các khai báo đã được khai báo trước đó, vì vậy * tất nhiên * nó hoạt động, nhưng dù sao cũng đáng ngạc nhiên. –

+0

@MatthieuM., Thuật ngữ đằng sau 'twist' là, bạn rất có thể bao gồm cả hai chuyên môn riêng biệt trong 2 tệp tiêu đề khác nhau và sử dụng chúng trong các tệp .cpp khác nhau. Mọi thứ sẽ luôn biên dịch tốt đẹp. Vấn đề sẽ chỉ xảy ra khi cả hai được hiển thị cho bất kỳ instantiation. – iammilind

1

Ah, nhưng chúng là không giống nhau vì chúng không sử dụng cùng thông số. Sử dụng kêu vang và ví dụ ban đầu của bạn:

#include <cstdio> 

template <class x1, class x2> 
struct CoreTemplate { }; 

template <class x1, class x2> 
struct CoreTemplate<x1*, x2*> { int spec; CoreTemplate() { spec = 1; } }; 
// note: partial specialization matches [with x1 = int, x2 = int] 

template <class x1, class x2> 
struct CoreTemplate<x2*, x1*> { int spec; CoreTemplate() { spec = 2; } }; 
// note: partial specialization matches [with x1 = int, x2 = int] 

int main() 
{ 
    CoreTemplate<int*, int*> qq; 
    // error: ambiguous partial specializations of 'CoreTemplate<int *, int *>' 
    std::printf("var=%d.\r\n", qq.spec); 
} 

Tuy nhiên nếu chúng ta tinh chỉnh các chuyên ngành một phần để họ có chính xác phù hợp:

template <class x1, class x2> 
struct Core { }; 

template <class x1> 
struct Core<x1*, x1*> { int spec; Core() { spec = 1; } }; 
// note: previous definition is here 

template <class x1> 
struct Core<x1*, x1*> { int spec; Core() { spec = 2; } }; 
// error: redefinition of 'Core<type-parameter-0-0 *, type-parameter-0-0 *>' 

Vì vậy, nó chỉ có vẻ là một chất lượng về vấn đề thực hiện. Một trình biên dịch có thể phát ra một cảnh báo cho trường hợp đầu tiên, nhưng nó có thể là tài nguyên tiêu thụ trong trường hợp chung hoặc nó có thể chỉ là không ai thể hiện nhu cầu cho đến nay.

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