2010-11-04 17 views
11

Nói rằng tôi có một lớp templated:Gọi phiên bản không chuyên biệt của một hàm khi chuyên dùng trong C++?

template <typename T> 
class foo { 
    void do_someting(T obj) { 
    // do something generic... 
    } 
}; 

và tôi muốn chuyên do_something, nhưng bên trong nó tôi muốn gọi là "bình thường" chức năng do_something:

template<> 
void foo<MyObj>::do_something(MyObj obj) { 
    // do something specific... 
    // and ALSO do something generic! 
} 

là có một cách để tham khảo đến phiên bản bình thường của do_something trong chức năng chuyên môn của tôi? Hay tôi chỉ cần sao chép mã?

(Tôi biết rằng tôi có thể refactor foo theo cách mà tôi sẽ không có vấn đề này chính xác, nhưng khi nó xảy ra tôi không thể thực sự sửa đổi foo "thực", vì nó là mã chia sẻ nhiều.)

+4

Không có phiên bản "bình thường" của 'do_something' cho loại' MyObj' - toàn bộ hiệu ứng của chuyên môn mẫu là * thay thế * instantiation mà bạn sẽ có được từ mẫu cơ sở, với lớp/chức năng bạn xác định trong chuyên môn. –

+0

có thể trùng lặp của [Làm thế nào tôi có thể nhận được một mẫu chuyên biệt để sử dụng phiên bản không chuyên biệt của một chức năng thành viên?] (Http://stackoverflow.com/questions/347096/how-can-i-get-a-specialized-template- –

+1

Phải, nhưng trình biên dịch biết về mã trong foo :: do_something, không có lý do tại sao nó không thể cho phép tôi tham chiếu đến nó bằng cách nào đó. Tôi hoàn toàn sẵn sàng tin rằng tính năng ngôn ngữ này không tồn tại, mặc dù --- đó là những gì tôi đang cố gắng tìm ra. –

Trả lời

7

Không. Chuyên môn của bạn là định nghĩa duy nhất sẽ tồn tại đối với loại đối số MyObj. Nhưng, hãy xem xét sửa đổi mẫu foo theo cách này, mà sẽ là trong suốt đối với người dùng hiện tại của mẫu:

template<typename T> 
class foo { 
    void prelude(T &obj){ // choose a better name 
    /* do nothing */ 
    } 
    void do_something(T obj){ 
    prelude(obj); 
    // do something generic... 
    } 
}; 

Sau đó xác định một chuyên môn hóa cho khúc dạo đầu:

template<> 
void foo<MyObj>::prelude(MyObj &obj){ 
    // do something specific 
} 

này là hơi tương tự trong cấu trúc cho main use case for private virtual members. (Phân loại của. Không thực sự. Nhưng đó là những gì truyền cảm hứng cho tôi trong câu trả lời này.)

+0

điều này trông giống như một tương tự mẫu thế giới cho NVI của Sutter! –

1

Bạn cũng có thể xem xét một loại không phải MyObj, nhưng ngầm chuyển đổi sang nó, nhưng cách tốt nhất là tái cấu trúc và có thể trích xuất chung chung một cái gì đó.

#include <iostream> 
#include <boost/ref.hpp> 
typedef int MyObj; 


template <typename T> 
struct foo { 
    void do_something(T obj) { 
    // do something generic... 
    std::cout << "generic " << obj << '\n'; 
    } 
}; 

template<> 
void foo<MyObj>::do_something(MyObj obj) { 
    // do something specific... 
    std::cout << "special " << obj << '\n'; 
    // and ALSO do something generic! 
    foo<boost::reference_wrapper<MyObj> >().do_something(boost::ref(obj)); 
} 

int main() 
{ 
    foo<int> f; 
    f.do_something(10); 
} 
0

Vâng, điều này thực sự khá đơn giản. Bạn chỉ cần để cho phiên bản chính, chung của hàm của bạn đóng vai trò là một hàm chuyển tiếp thành hàm chung 'triển khai' mà không nhận được một phần chuyên biệt, sau đó bạn có thể gọi nó từ phiên bản chuyên biệt của hàm ban đầu khi cần .

template <typename T> 
class foo 
{ 
    void do_something(T obj) 
    { 
    do_something_impl(obj); 
    } 

    void do_something_impl(T obj) 
    { 
    // do something generic... 
    } 
}; 

Bây giờ chuyên môn có thể gọi phiên bản generic mà không có một vấn đề:

template<> 
void foo<MyObj>::do_something(MyObj obj) 
{ 
    // do something specific... 
    do_something_impl(obj); //The generic part 
} 

Tôi nghĩ rằng đây gần gũi hơn với ý định ban đầu của bạn hơn câu trả lời Steve M., và là những gì tôi làm khi đối mặt với vấn đề này.

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