2009-04-20 41 views
8

Tôi đang cố triển khai một hàm mẫu có các chốt điều khiển khác nhau bằng cách sử dụng chuyên môn mẫu.chuyên môn mẫu cho các hàm thành viên tĩnh; làm thế nào để?

Các mã sau đây mang lại cho tôi một "chuyên môn hóa rõ ràng trong phạm vi không gian tên" trong gcc:

template <typename T> 
static T safeGuiCall(boost::function<T()> _f) 
{ 
    if (_f.empty()) 
     throw GuiException("Function pointer empty"); 
    { 
     ThreadGuard g; 
     T ret = _f(); 
     return ret; 
    } 
} 

// template specialization for functions wit no return value 
template <> 
static void safeGuiCall<void>(boost::function<void()> _f) 
{ 
    if (_f.empty()) 
     throw GuiException("Function pointer empty"); 
    { 
     ThreadGuard g; 
     _f(); 
    } 
} 

Tôi đã cố gắng di chuyển nó ra khỏi lớp (lớp không được templated) và vào namespace nhưng sau đó tôi nhận được lỗi "Chuyên sâu rõ ràng không thể có một lớp lưu trữ". Tôi đã đọc nhiều cuộc thảo luận về điều này, nhưng mọi người dường như không đồng ý làm thế nào để chuyên về các mẫu chức năng. Bất kỳ ý tưởng?

Trả lời

12

Khi bạn chuyên một phương pháp templated, bạn phải làm như vậy bên ngoài dấu ngoặc lớp:

template <typename X> struct Test {}; // to simulate type dependency 

struct X // class declaration: only generic 
{ 
    template <typename T> 
    static void f(Test<T>); 
}; 

// template definition: 
template <typename T> 
void X::f(Test<T>) { 
    std::cout << "generic" << std::endl; 
} 
template <> 
inline void X::f<void>(Test<void>) { 
    std::cout << "specific" << std::endl; 
} 

int main() 
{ 
    Test<int> ti; 
    Test<void> tv; 
    X::f(ti); // prints 'generic' 
    X::f(tv); // prints 'specific' 
} 

Khi bạn mang nó bên ngoài của lớp, bạn phải loại bỏ các từ khóa 'tĩnh'. Từ khóa tĩnh bên ngoài lớp có một ý nghĩa cụ thể khác với những gì bạn có thể muốn.

template <typename X> struct Test {}; // to simulate type dependency 

template <typename T> 
void f(Test<T>) { 
    std::cout << "generic" << std::endl; 
} 
template <> 
void f<void>(Test<void>) { 
    std::cout << "specific" << std::endl; 
} 

int main() 
{ 
    Test<int> ti; 
    Test<void> tv; 
    f(ti); // prints 'generic' 
    f(tv); // prints 'specific' 
} 
+0

hm Tôi đã thử điều tương tự bây giờ, nhưng đặt nó trong một tập tin .hpp và cố gắng bao gồm nó ... sau đó tôi nhận được lỗi "nhiều định nghĩa của vodi X: ff (Kiểm tra ). Tôi không thể thấy điều gì sẽ – Rolle

+1

Đó có phải là lỗi trình biên dịch hoặc liên kết không?Nếu đó là lỗi trình biên dịch có nghĩa là bạn có thể bao gồm tiêu đề mẫu nhiều hơn một lần và các tiêu đề bảo vệ bị thiếu và do đó định nghĩa kép: trình biên dịch nhìn thấy hai định nghĩa chính xác để thực hiện. –

+0

Tại sao tôi nên thêm nội tuyến cho trường hợp đầu tiên? Nếu không, tôi nhận được một lỗi biên dịch. – sop

3

Bạn có thể khai báo chuyên môn hóa rõ ràng trong cùng một cách bạn muốn định nghĩa một hàm thành viên bên ngoài lớp học của nó:

class A 
{ 
public: 
    template <typename T> 
    static void foo() {} 
}; 

template <> 
void A::foo<void>() 
{ 
} 
+0

Cảm ơn câu trả lời. Đối với tôi nó không quan trọng nếu họ đang ở trong một lớp học hay không; nhưng tôi không thể làm cho nó hoạt động một trong hai cách. Cú pháp của tôi sai hay một cái gì đó trong mã tôi đã cung cấp? – Rolle

+0

Vấn đề là bạn rõ ràng chuyên hàm trong không gian tên với một trình khai báo hàm đủ điều kiện. C++ không cho phép bạn thêm lại từ khóa 'tĩnh' để bạn chỉ xóa nó. Ví dụ của tôi ở trên cho bạn thấy làm thế nào để một cách rõ ràng chuyên một thành viên tĩnh. –

2

Vấn đề của bạn dường như là với boost :: Chức năng - các chuyên ngành sau đây làm việc:

+0

xin lỗi đã thử nhưng không hoạt động. Bạn đã biên dịch theo gcc? Tôi nghĩ rằng nó hoạt động theo VS ví dụ ... – Rolle

+0

Đây là phiên bản g ++ 3.4.5 –

+0

Đây là số liệu thống kê - loại bỏ chúng và tất cả phải là weel, nó biên dịch với comeau, tôi sẽ cập nhật câu trả lời –

4

Nó không phải trực tiếp một câu trả lời cho câu hỏi của bạn, nhưng bạn có thể viết này

template <typename T> 
static T safeGuiCall(boost::function<T()> _f) 
{ 
     if (_f.empty()) 
       throw GuiException("Function pointer empty"); 
     { 
       ThreadGuard g; 
       return _f(); 
     } 
} 

Nó sẽ hoạt động ngay cả khi _f() trả lại 'void'

Chỉnh sửa: Trong trường hợp tổng quát hơn, tôi nghĩ chúng ta nên thích quá tải hàm thay vì chuyên môn hóa. Dưới đây là một lời giải thích tốt cho việc này: http://www.gotw.ca/publications/mill17.htm

+1

có điểm rất tốt –

+0

I Tôi khá chắc chắn rằng nó sẽ không hoạt động. T không được định nghĩa ở đâu? – Rolle

+0

@Rolle Xin lỗi "mẫu " không tồn tại để sao chép/dán. – Rexxar

1

Tôi gặp sự cố tương tự. Nếu bạn nhìn vào bài viết gốc, tôi để lại cái tĩnh đầu tiên, nhưng lấy ra lỗi thứ hai và BOTH đã biến mất.

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