2012-01-21 53 views
6
#include <iostream> 
template <class T> 
void foo(T) { 
    std::cout << "foo(T)" << std::endl; 
} 

template <class T> 
void foo(T*) { //#3 
    std::cout << "foo(T*)" << std::endl; 
} 

#define TEST 

#ifdef TEST 
template <> 
void foo(int*) { //#1 
    std::cout << "foo(int*)" << std::endl; 
} 
#else 
template <> 
void foo<int*>(int*) { //#2 
    std::cout << "foo<int*>(int*)" << std::endl; 
} 
#endif 

int main(int argc, char **argv) { 
    int* p = 0; 
    foo(p); 
    return 0; 
} 

sự khác biệt giữa # 1 và # 2 là gì. Nếu tôi xác định TEST, công việC# 1. Nhưng nếu tôi nhận xét nó, # 3 hoạt động ... Và đó là cách đúng để viết chuyên môn mẫu chức năng ...chuyên môn mẫu chức năng không thành công?

Trả lời

3

# 1 tuyên bố mẫu chuyên môn của số 3 và tự động suy ra các tham số mẫu. # 2 là một chuyên môn của mẫu đầu tiên bạn đã xác định (mẫu không có số, hãy gọi nó là # 0) cho T=int*. Nó không thể là chuyên môn hóa # 3 vì thay thế T bằng chỉ định int* sẽ dẫn đến thông số int**.

Khi bạn gọi số foo, trước tiên, độ phân giải quá tải sẽ chọn mẫu cơ sở phù hợp nhất, sau đó kiểm tra mẫu đó cho bất kỳ chuyên môn hiện có nào. Với TEST được xác định, có hai mẫu cơ bản (# 0 và # 3) và # 3 là một kết hợp tốt hơn và được chọn. Sau đó trình biên dịch kiểm tra các chuyên ngành của khuôn mẫu đó, và # 1 phù hợp hơn và đang được gọi.

Nếu không có TEST được xác định, vẫn còn hai mẫu cơ sở (# 0 và # 3) và # 3 là kết hợp tốt hơn và được chọn.Sau đó trình biên dịch kiểm tra các chuyên ngành của mẫu đó, nhưng vì # 2 chuyên về # 0 chứ không phải # 3, nó không được xem xét và kết thúC# 3 được gọi.

Đây là ví dụ cổ điển của Why not Specialize Function Templates. Các vấn đề được giải thích chi tiết hơn ở đó.

Giải pháp đơn giản là không chuyên chức năng mẫu ở tất cả, nhưng chỉ cần thêm quá tải mới cho các loại đặc biệt:

// no template, just a normal function 
void foo(int*) { 
    std::cout << "foo(int*)" << std::endl; 
} 
0

Tôi thực sự không thể biết được chức năng nào được yêu cầu chuyên môn, hoặc chính xác như thế nào quy tắc giải quyết quá tải cực kỳ phức tạp sẽ chọn chức năng để gọi.

Tôi biết rằng bạn thường không cần để chuyên chức năng, nhưng có thể dựa vào quá tải thay thế. Để có được một chức năng cho int* bạn chỉ cần

void foo(int*) { 
    std::cout << "foo(int*)" << std::endl; 
} 

Một chức năng không mẫu sẽ được ưa thích hơn mẫu, miễn là các thông số phù hợp.

+0

Có một số tình huống mà nó là thuận tiện hoặc cần thiết để xác định các mẫu tranh luận (s) . Nơi rõ ràng khi cần thiết để xác định các đối số là nếu đối số mẫu không được suy luận. Những nơi thuận tiện là khi bạn cần hướng đối số đến loại được chuyển đổi thích hợp. Khi bạn muốn xác định rõ ràng đối số bạn thường không thể sử dụng quá tải. –

2

Đối với các chuyên môn mẫu chức năng, bạn có thể liệt kê rõ ràng các đối số mẫu nhưng bạn không phải thực hiện các đối số mẫu. Nếu bạn không chỉ định các đối số mẫu, chúng được suy ra bởi trình biên dịch bằng cách sử dụng các quy tắc tương tự như độ phân giải quá tải. Để quyết định chọn quá tải hàm nào, trình biên dịch bắt đầu bằng việc chỉ xem xét các mẫu chính (được chọn bởi một số quy trình phép thuật ở nơi đầu tiên). Xem hai mẫu chính có sẵn

template <typename T> void foo(T); 
template <typename T> void foo(T*); 

tùy chọn sau là đối sánh tốt hơn cho đối số con trỏ. Khi tìm thấy mẫu chính thích hợp, trình biên dịch tìm các chuyên ngành tiềm năng của mẫu chính này. Tuy nhiên, ví dụ # 2 của bạn thực sự không phải là một chuyên môn của mẫu hàm lấy tham số con trỏ mặc dù nó liên quan đến một đối số con trỏ. Nếu bạn mất việc kê khai chính

template <typename T> void foo(T*); 

và bạn thay thế T bởi các mẫu đối số quy định một cách rõ ràng int* bạn nhận được

template <> void foo<int*>(int**); 

Đó là, việc kê khai

template <> void foo<int*>(int*); 

là một cái gì đó khác nhau. Bạn có thể chỉ muốn mất con trỏ khi chỉ định đối số mẫu:

template <> void foo<int>(int*); 
+1

Tại sao bạn nói '# 2' không nên biên dịch? Nó phù hợp với mẫu đầu tiên, 'mẫu void foo (T)' với 'T = int *'. –

+0

@AaronMcDaid Ồ, xin lỗi, bạn nói đúng: Tôi không thấy rằng có hai mẫu chính và câu hỏi trở thành cái nào trong số này được sử dụng. Tuy nhiên, vì phiên bản phiên bản con trỏ của kết hợp chính là một lựa chọn tốt hơn, mẫu này sẽ được chọn ngay cả khi chuyên môn của nó là một kết hợp tốt hơn: độ phân giải quá tải hoạt động theo các mẫu chính. Khi mẫu chức năng được quyết định, chọn chuyên môn thích hợp. Tôi đoán, tôi nên chỉnh sửa câu trả lời để phản ánh điều này ... –

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