2010-03-23 52 views
12

Khi tôi chuyên hàm/hằng số thành viên (tĩnh) trong một lớp mẫu, tôi bị nhầm lẫn là nơi khai báo có nghĩa là để đi.Khai báo chuyên môn thành viên của lớp mẫu

Dưới đây là một ví dụ về những gì tôi phải làm gì - yoinked trực tiếp từ IBM's reference on template specialization:

=== IBM Member Chuyên Ví dụ ===

template<class T> class X { 
public: 
    static T v; 
    static void f(T); 
}; 

template<class T> T X<T>::v = 0; 
template<class T> void X<T>::f(T arg) { v = arg; } 

template<> char* X<char*>::v = "Hello"; 
template<> void X<float>::f(float arg) { v = arg * 2; } 

int main() { 
    X<char*> a, b; 
    X<float> c; 
    c.f(10); // X<float>::v now set to 20 
} 

Câu hỏi đặt ra là, làm thế nào để tôi chia này vào tệp header/cpp? Việc thực hiện chung là rõ ràng trong tiêu đề, nhưng những gì về chuyên môn?

Nó không thể đi trong tập tin tiêu đề, bởi vì nó là cụ thể, dẫn đến nhiều định nghĩa. Nhưng nếu nó đi vào tập tin .cpp, là mã mà gọi X :: f() nhận thức của chuyên môn, hoặc nó có thể dựa vào chung X :: f()?

Cho đến nay tôi chỉ có chuyên môn trong .cpp, không có khai báo trong tiêu đề. Tôi không gặp khó khăn khi biên dịch hoặc thậm chí chạy mã của tôi (trên gcc, không nhớ phiên bản tại thời điểm này), và nó hoạt động như mong đợi - công nhận chuyên môn hóa. Nhưng A) Tôi không chắc điều này là chính xác, và tôi muốn biết cái gì là, và B) tài liệu Doxygen của tôi xuất hiện rất lạc quan và rất gây hiểu lầm (thêm vào đó trong một thời điểm câu hỏi sau).

Những gì có vẻ tự nhiên nhất đối với tôi sẽ là một cái gì đó như thế này, tuyên bố chuyên môn hóa trong tiêu đề và xác định nó trong cpp:

=== XClass.hpp ===

#ifndef XCLASS_HPP 
#define XCLASS_HPP 

template<class T> class X { 
public: 
    static T v; 
    static void f(T); 
}; 

template<class T> T X<T>::v = 0; 
template<class T> void X<T>::f(T arg) { v = arg; } 

/* declaration of specialized functions */ 
template<> char* X<char*>::v; 
template<> void X<float>::f(float arg); 

#endif 

=== XClass.cpp ===

#include <XClass.hpp> 

/* concrete implementation of specialized functions */ 
template<> char* X<char*>::v = "Hello"; 
template<> void X<float>::f(float arg) { v = arg * 2; } 

... nhưng tôi không biết điều này có đúng không. Bất kỳ ý tưởng?

Trả lời

9

Thông thường, bạn chỉ cần xác định các chuyên môn inline trong tiêu đề như đã nói một cách dirady.

Bạn có thể định nghĩa chuyên ngành trong các đơn vị dịch riêng biệt tuy nhiên nếu bạn đang lo lắng về thời gian biên dịch hoặc sưng lên mã:

// x.h: 
template<class T> struct X { 
    void f() {} 
} 

// declare specialization X<int>::f() to exist somewhere: 
template<> void X<int>::f(); 

// translation unit with definition for X<int>::f(): 
#include "x.h" 
template<> void X<int>::f() { 
    // ... 
} 

Vì vậy, có, cách tiếp cận của bạn trông tốt. Lưu ý rằng bạn chỉ có thể thực hiện việc này với chuyên môn đầy đủ, do đó thường không thực tế để thực hiện việc này.

Để biết chi tiết, xem ví dụ: Comeaus template FAQ.

+1

Câu hỏi, trong sự tò mò: tại sao ưu tiên cho nội tuyến? Có vẻ như một "yêu cầu" kỳ lạ để áp đặt - rằng "theo mặc định" một chuyên môn về mẫu sẽ được gạch chân. Tôi hỏi tất cả điều này chỉ vì bạn ngụ ý rằng đó là những gì bạn sẽ "thường" làm, và tôi không thấy lý do tại sao tôi muốn thường làm điều đó nhiều hơn tôi muốn thường tuyên bố bất kỳ nội tuyến chức năng khác. – Ziv

+0

Về sở thích của chúng cho việc đặt chúng vào tiêu đề, 'nội tuyến' là một tác dụng phụ. Ít để viết, cơ hội tối ưu hóa nhiều hơn, không có lỗi bằng cách quên một tuyên bố. Ngoài ra, bạn luôn cần phải hoàn toàn chuyên và đối với hầu hết các mẫu có nghĩa là thêm một khai báo và khởi tạo rõ ràng cho mọi kết hợp các loại được sử dụng. Loại đánh bại ý định của sự hào phóng, phải không? –

+0

Vâng, tất nhiên tôi chỉ nói về các trường hợp khi một chuyên môn đầy đủ là những gì mong muốn, nếu không nó rõ ràng là một câu chuyện hoàn toàn khác ... Lật câu hỏi, sau đó: tại sao những lợi thế đó không khiến chúng ta thích thường viết tất cả các hàm nội tuyến? – Ziv

4

Đặt tất cả trong một tệp hpp. Tạo các chuyên môn và bất kỳ thứ gì bạn xác định bên ngoài lớp inline - điều đó sẽ quản lý nhiều định nghĩa.

+0

Thú vị. Nhưng điều này không làm việc cho các biến tĩnh - chỉ cho các hàm. Điều đó sang một bên - không có cách nào thanh lịch/tiêu chuẩn hơn để giải quyết vấn đề này? Chuyên môn thành viên của lớp mẫu là một phần chính trong lập trình mẫu. Chắc chắn "nơi nào bạn đặt tuyên bố" có một câu trả lời đơn giản hơn "tuyên bố nội tuyến và đánh lừa trình biên dịch"? – Ziv

+0

@Ziv: Tôi nghĩ rằng các biến tĩnh sẽ không hoạt động trong tiêu đề, nhưng tôi đã thử điều này trong VS2008 và có vẻ như nó hoạt động. – quamrana

+1

Các chuyên ngành có thể được xác định trong tệp nguồn hoặc nội tuyến trong tiêu đề, nhưng phải được khai báo trong tiêu đề. –

0

Để trả lời một câu hỏi của bạn: is code which calls X::f() aware of the specialization, or might it rely on the generic X::f()?

Nếu trình biên dịch thấy một định nghĩa mà phù hợp với yêu cầu của nó, sau đó nó sẽ sử dụng nó. Khác nó sẽ tạo ra các cuộc gọi chức năng bình thường.

Trong đoạn mã đầu tiên, bạn cung cấp định nghĩa chung cho X<T>::f(T arg), do đó trình biên dịch sẽ khởi tạo cho bất kỳ T ngoài số float.

Nếu bạn bỏ qua định nghĩa chung, trình biên dịch sẽ tạo các cuộc gọi đến, giả sử, X<double>::f(double) và trình liên kết sẽ tìm kiếm định nghĩa có thể kết thúc bằng lỗi trình liên kết.

Để tóm tắt: Bạn có thể có mọi thứ trong tiêu đề, vì dưới dạng mẫu, bạn sẽ không nhận được nhiều định nghĩa. Nếu bạn chỉ có các khai báo, bạn sẽ cần các định nghĩa ở nơi khác để liên kết tìm thấy sau này.

+0

Câu hỏi của tôi là cách khác xung quanh: nếu/ở đâu/cách đặt tờ khai chuyên ngành. Một định nghĩa mẫu chuyên biệt * không thể * đi trong tiêu đề (trừ khi được gạch chân, như được đề xuất một cách rõ ràng). Làm cách nào để đảm bảo rằng X :: f() gọi cho chuyên môn và không gọi nhầm định nghĩa chung? – Ziv

+0

@Ziv: Các thử nghiệm của tôi, trái với mong đợi của tôi, nói rằng mọi thứ * có thể * đi trong tiêu đề, chuyên môn tĩnh và tất cả. – quamrana

+0

Điều đó thật kỳ quặc. Tôi đã thử điều đó và tôi nhận được lỗi "được định nghĩa nhiều ...". Yay trình biên dịch phù hợp! – Ziv

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