2013-02-25 48 views
11

Tôi có một lớp mẫu mà tôi khai báo trong tiêu đề với một phương pháp và không định nghĩa phương thức đó trong tiêu đề. Trong tệp .cc, tôi xác định chuyên môn của phương thức đó mà không bao giờ khai báo chúng trong tiêu đề. Trong một tệp .cc khác, tôi gọi phương thức cho các tham số mẫu khác nhau mà các chuyên môn tồn tại. Nó trông giống như thế này:Chuyên môn thành viên của lớp mẫu mà không cần khai báo trong tiêu đề

foo.h:

template<typename T> 
class Foo { 
public: 
    static int bar(); 
}; 

foo.cc:

#include "foo.h" 

template<> 
int Foo<int>::bar() { 
    return 1; 
} 

template<> 
int Foo<double>::bar() { 
    return 2; 
} 

main.cc:

#include <iostream> 
#include "foo.h" 

int main(int argc, char **argv) { 
    std::cout << Foo<int>::bar() << std::endl; 
    std::cout << Foo<double>::bar() << std::endl; 
    return 0; 
} 

Chương trình này biên dịch và liên kết thành công với gcc 4.7.2 cho tất cả các tiêu chuẩn C++ (C++ 98, gnu ++ 98, C++ 11 và gnu ++ 11). Đầu ra là:

1 
2 

Điều này có ý nghĩa với tôi. Do đơn vị dịch main.cc không thấy định nghĩa là bar() hoặc bất kỳ chuyên môn nào của nó, nó mong đợi các cuộc gọi đến bar() để sử dụng các cảnh báo rõ ràng của định nghĩa không được chỉ định của bar() trong một số đơn vị dịch khác. Nhưng kể từ khi mang tên có thể dự đoán được, các chuyên ngành trong foo.cc có cùng tên biểu tượng như là các instantiation rõ ràng của một định nghĩa không chuyên biệt, do đó, main.cc có thể sử dụng các chuyên ngành đó mà không cần chúng được khai báo trong đơn vị dịch đó.

Câu hỏi của tôi là: đây có phải là tai nạn hay hành vi này được bắt buộc theo tiêu chuẩn C++? Nói cách khác, mã này có phải là di động không?

Câu hỏi trước có liên quan nhất mà tôi có thể tìm thấy là Declaration of template class member specialization, nhưng không bao gồm trường hợp cụ thể này.

(Trong trường hợp bạn tự hỏi tại sao điều này lại quan trọng với tôi, đó là vì tôi đang sử dụng mã như thế này như một bảng tra cứu thời gian biên dịch và ngắn hơn rất nhiều nếu tôi không khai báo chuyên môn .)

+2

Đây là câu hỏi đầu tiên khá tốt! Tôi nghĩ rằng trình biên dịch của IBM cho phép bạn khai báo các chuyên môn của bạn bằng cách sử dụng từ khóa extern, nhưng không bao giờ tự mình thực hiện nó. –

Trả lời

8

Tiêu chuẩn (C++ 11) đòi hỏi chuyên môn rõ ràng được công bố (nhưng không nhất thiết phải định nghĩa) trước khi chúng được sử dụng đầu tiên:

(14.7.3/6) Nếu một mẫu, một mẫu thành viên hoặc một thành viên của một mẫu lớp là chuyên môn một cách rõ ràng thì chuyên môn đó phải được khai báo trước khi sử dụng lần đầu tiên chuyên môn đó có thể gây ra một sự diễn giải tiềm ẩn xảy ra, trong mọi tra cứu đơn vị nslation trong đó sử dụng như vậy xảy ra; không cần chẩn đoán. Nếu chương trình không cung cấp định nghĩa cho một chuyên môn rõ ràng và chuyên môn được sử dụng theo cách sẽ gây ra sự diễn giải ngầm hoặc thành viên là chức năng thành viên ảo, chương trình bị hỏng, không cần chẩn đoán . An instantiation ngầm không bao giờ được tạo ra cho một chuyên môn rõ ràng được khai báo nhưng không được xác định. [...]

Tôi tin rằng điều này sẽ thực tế chỉ có tác dụng khi định nghĩa mẫu chính của bạn bao gồm định nghĩa phiên bản không chuyên môn của một trong các chức năng thành viên. Bởi vì trong trường hợp đó, khi chuyên môn rõ ràng không được khai báo, định nghĩa chính hiện tại có thể được sử dụng để biên dịch hàm nội tuyến thành mã, và chuyên môn hóa sẽ không được sử dụng ở thời gian liên kết.

Nói cách khác, nếu không có định nghĩa về hàm thành viên có trong định nghĩa mẫu chính, thì trình liên kết của bạn có thể được mong đợi làm việc trong thực tế, nhưng nó không phù hợp với tiêu chuẩn nói và có thể khiến bạn gặp rắc rối thực sự ngay sau khi bạn thêm định nghĩa hàm nội tuyến vào mẫu chính.

+0

Cảm ơn. Chắc chắn đồng ý rằng mã này bị hỏng nếu có định nghĩa nội tuyến trong mẫu chính. Nhưng nếu không có, tiêu chuẩn có nói gì về những gì xảy ra trong trường hợp này không? Đoạn đó dường như không bao gồm nó. –

+0

@TristanSchmelcher Tôi tin rằng phần trên bao gồm tất cả các trường hợp (trừ khi có ngoại lệ ở đâu đó mà tôi không thấy). Nó nói rõ ràng rằng các chuyên môn rõ ràng phải được khai báo trước khi sử dụng. Vì vậy, nếu tập tin tiêu đề không khai báo nó, nhưng main.cpp (trong đó bao gồm tiêu đề, nhưng không phải là .cc) sử dụng nó, nó vi phạm tiêu chuẩn. – jogojapan

+1

Tôi hiểu. Tôi nghĩ thuật ngữ "ngầm định ngầm" sẽ không bao hàm việc sử dụng trong main.cc vì không có định nghĩa nào về 'bar()' không chuyên biệt trong phạm vi, nhưng 14.7.1 dường như nói rằng nó được tính là một sự khởi tạo ngầm bất kể. –

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