2013-06-04 45 views
7

Tôi đang cố gắng truy cập chức năng thành viên tĩnh được xác định bên trong mẫu lớp. Trong tập tin tiêu đề TemplateTest.h tôi xác định Mẫu lớp tiểu học như:chức năng thành viên tĩnh bên trong chuyên môn mẫu lớp

#include<iostream> 

template<class T, class U> 
struct TemplateTest 
{ 
public: 
    void static invoke(); 
    /*{ 

     std::cout << "Should not be called" << std::endl; 

    }*/ 
}; 

Sau đó Nguồn tập tin TemplateTester.cpp tôi đặt một chuyên môn:

#include "TemplateTest.h" 

template<> 
struct TemplateTest<int, bool> 
{ 
    static void invoke() 
    { 
     std::cout << "invoke<int, bool>" << std::endl; 
    } 
}; 

template struct TemplateTest<int, bool>; //instantiate to resolve linker issue 

tôi một cách rõ ràng khởi tạo các lớp học với giải quyết nên mối liên kết đúng.

Trong driver.cpp tài xế:

include "TemplateTest.h" 

int main() 
{ 
    TemplateTest<int, bool>::invoke(); 
    return 0; 
} 

Khi tôi biên dịch TemplateTest.cpp với g ++ nó tạo ra các tập tin đối tượng một cách chính xác nhưng khi tôi cố gắng liên kết nó với các lớp lái xe nó mang lại cho lỗi mối liên kết của tôi " undefined reference to `TemplateTest :: invoke()"

Tôi đã đi qua các bài đăng liên quan khác như this one nhưng tôi không cố gắng truy cập một mẫu chức năng.

Mọi đầu mối đều được đánh giá cao.

+4

Di chuyển triển khai sang tệp tiêu đề. triển khai khuôn mẫu cần phải được hiển thị cho tất cả TU sử dụng chúng. –

Trả lời

5

Bạn đúng rằng tệp đối tượng bạn tạo từ TemplateTester.cpp sẽ chứa biểu tượng cho chuyên môn bạn đã cung cấp. Đây là trường hợp bởi vì bất kỳ chuyên môn rõ ràng nào khiến cho mẫu được khởi tạo, và đó là gấp đôi trường hợp bởi vì bạn thậm chí còn thêm một instantiation rõ ràng (mà thực sự là không cần thiết).

Tuy nhiên, tại thời điểm khi driver.cpp được biên soạn, trình biên dịch không biết về chuyên môn, bởi vì bạn chỉ bao gồm TemplateTester.h và chuyên môn không được đề cập ở đó. Vì vậy, trình biên dịch instantiates mẫu, tất nhiên là không sử dụng định nghĩa chuyên biệt, vì vậy bạn sẽ gặp phải vấn đề của mình.

Tiêu chuẩn nói (In nghiêng của tôi):

(§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 chuyên biệt 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 đó sẽ gây ra một sự diễn giải ngầm định diễn ra, trong mọi đơn vị dịch thuật mà việc 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 có thể gây ra sự khởi tạo ngầm định hoặc thành viên là chức năng thành viên ảo, chương trình không đúng chuẩn, 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. [...]

Vì vậy, bạn cần phải thực hiện cả hai, việc khai báo và định nghĩa của chuyên môn hóa được biết đến với các trình biên dịch khi nó hoạt động trên driver.cpp. Cách tốt nhất để làm điều này là thêm toàn bộ chuyên môn vào TemplateTester.h.

Lưu ý, một lần nữa, việc khởi tạo rõ ràng là không thực sự bắt buộc.

+1

Cảm ơn bạn đã giải thích @jogojapan. Đây thực sự là một mẫu thử nghiệm của thư viện mẫu tĩnh mà tôi đang làm việc. Bây giờ tôi có thể thấy lý do tại sao nó không thành công Tôi đoán tôi có thể di chuyển các định nghĩa để giữ cho trình biên dịch hài lòng. – jazaman

3

Có một số vấn đề:

  • bạn không cần phải nhanh chóng một cách rõ ràng mẫu đầy đủ chuyên
  • nếu bạn muốn đưa phương pháp tĩnh của bạn trong tiêu đề, sau đó sử dụng inline. Nếu không, bạn sẽ nhận được nhiều trường hợp và sự cố liên kết
  • chuyên môn mẫu bạn đặt trong tiêu đề và xác định các phương pháp trong các tệp nguồn
  • nếu bạn không muốn thứ gì đó được gọi trong mẫu, bạn không cần phải xác định nó. Bạn sẽ nhận được lỗi trình biên dịch, và điều đó có nghĩa là bắt lỗi trước đó.

// TemplateTest.h 
#include<iostream> 

template<class T, class U> 
struct TemplateTest; 
template<> 
struct TemplateTest<int, bool> 
{ 
    inline static void invoke() 
    { 
     std::cout << "invoke<int, bool>" << std::endl; 
    } 
}; 

// main.cpp 
include "TemplateTest.h" 

int main() 
{ 
    TemplateTest<int, bool>::invoke(); 
} 

Một cách khác là thay đổi tiêu đề, và thêm các tập tin nguồn.

// TemplateTest.h 
#include<iostream> 

template<class T, class U> 
struct TemplateTest; 

template<> 
struct TemplateTest<int, bool> 
{ 
    static void invoke(); 
}; 

// TemplateTest.cpp 
#include "TemplateTest.h" 
void TemplateTest<int, bool>::invoke() 
{ 
    std::cout << "invoke<int, bool>" << std::endl; 
} 
+0

Cảm ơn @ BЈовић Tôi thực sự đã cố gắng đưa ra một nguyên mẫu ở đây. Có lẽ tôi nên đề cập một cách rõ ràng họ. Các mẫu lớp thực sự là một phần của một thư viện tĩnh và do đó, tôi nghĩ rằng tôi vẫn sẽ cần sự khởi tạo. Nhưng bạn đúng, tôi không nên định nghĩa hàm bên trong lớp. Nó nên được thực hiện bên ngoài. Tôi sẽ thử điều đó và xem liệu nó có giải quyết được vấn đề của tôi hay không. – jazaman

+0

@jazaman Không, bạn không cần phải thực hiện các mẫu chuyên biệt đầy đủ, vì chúng giống như các lớp bình thường (không phải mẫu). Nếu bạn bao gồm tiêu đề của bạn ở một số nơi, bạn sẽ nhận được lỗi liên kết. –

+0

sau khi đọc câu trả lời khác tôi hiểu rằng nếu nó là trường hợp hoàn toàn chuyên biệt không cần phải làm điều đó nữa. – jazaman

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