2012-11-12 23 views
6

Tôi biết rằng cú pháp cho tuyên bố một phương pháp lớp mẫu trong một tiêu đề và xác định nó trong một tập tin nguồn diễn ra như vậy:C++ - Tờ khai riêng/độ nét cho mẫu hàm trong lớp mẫu

myclass.h

template <typename T> 
class MyClass { 
    public: 
    void method(T input); 
    private: 
    T privVar; 
}; 

MyClass.cpp

template <typename T> 
void MyClass<T>::method(T input) { 
    privVar = input; 
} 

Nhưng nếu phương pháp này cũng là một mẫu? Tôi đang thêm phương thức vào lớp basic_string và tôi muốn biết cách viết triển khai cho các hàm.

MyString.h

template <class _Elem = TCHAR, 
      class _Traits = std::char_traits<_Elem>, 
      class _Ax  = std::allocator<_Elem>> 
class String 
    : public std::basic_string<_Elem, _Traits, _Ax> { 
    private: 
    // Types for the conversion operators. 
    typedef  _Elem* _StrTy; 
    typedef const _Elem* _ConstStrTy; 

    //... 

    public: 
     // Conversion operators so 'String' can easily be 
     // assigned to a C-String without calling 'c_str()'. 
    operator _StrTy() const { 
     return const_cast<_StrTy>(this->c_str()); 
    } 

    operator _ConstStrTy() const { 
     return this->c_str(); 
    } 

    // ... Constructors ... 

    /*------------ Additional Methods ------------*/ 

    //! Converts a value of the given type to a string. 
    template <class _ValTy> static String ConvertFrom(_ValTy val); 

    //! Converts a string to the given type. 
    template <class _ValTy> static _ValTy ConvertTo(const String& str); 
    template <class _ValTy> _ValTy ConvertTo(void) const; 

    //! Checks if a string is empty or is whitespace. 
    static bool IsNullOrSpace(const String& str); 
    bool IsNullOrSpace(void) const; 

    //! Converts a string to all upper-case. 
    static String ToUpper(String str); 
    void ToUpper(void); 

    // ... 
}; 

Làm thế nào tôi có thể thực hiện template <class _ValTy> static String ConvertFrom(_ValTy val);? Bởi vì bây giờ không chỉ tôi cần phải xác định mẫu lớp, mà còn là khuôn mẫu hàm. Tôi đặt cược mã tôi sắp viết không hợp lệ, nhưng nó sẽ hiển thị những gì tôi đang cố gắng để hoàn thành:

MyString.cpp

template <class _Elem, class _Traits, class _Ax> 
template <class _ValTy> 
String<_Elem, _Traits, _Ax> String<_Elem, _Traits, _Ax>::ConvertFrom(_ValTy val) { 
    // Convert value to String and return it... 
} 

Tôi không tiên tiến ở tất cả với các mẫu. Không chỉ tôi rất nghi ngờ rằng ở trên là hợp lệ, nó có vẻ cồng kềnh để viết và không phải là rất dễ đọc. Làm thế nào tôi sẽ đi về việc thực hiện các phương thức mẫu, và các phương thức mẫu tĩnh trả về kiểu lớp riêng của nó? Bởi vì tôi không muốn định nghĩa chúng trong tiêu đề.

+1

Có lẽ bạn nên đọc: [Tại sao các mẫu chỉ có thể được triển khai trong tệp tiêu đề?] (Http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the- tập tin tiêu đề). –

+0

@JesseGood Điều đó cho tôi thấy rằng có một cách để thực hiện phương thức * bình thường * từ một lớp mẫu trong một tệp nguồn riêng biệt, nhưng không phải cách thực hiện các phương thức * templated * từ một lớp mẫu. Có lẽ tôi đang nhìn một cái gì đó trong bài viết, tôi không muốn là anh chàng đó. Tôi có nên từ bỏ và tiếp tục và xác định các phương thức lớp nội tuyến trong tệp tiêu đề không? –

+0

Nếu bạn chỉ đang cố gắng tách các nguyên mẫu khỏi chức năng cho các hàm/lớp mẫu, bạn có thể thử sử dụng mô hình .inl: nơi chức năng thực tế là tệp .inl và bạn bao gồm tệp đó ở cuối tệp tiêu đề của mình. – Alex

Trả lời

9

Trước khi trả lời câu hỏi của bạn, hãy để tôi nói trước: Đừng làm điều này. Mở rộng std::string bằng cách sử dụng các hàm miễn phí thay vào đó, giống như thư viện chuẩn thực hiện nhiều thuật toán. Ngoài ra tôi khuyên bạn nên thực hiện nó cho phạm vi thay vì chỉ string s nhưng điều đó chủ quan hơn.

Cũng lưu ý rằng std::string Tránh chuyển đổi ngầm thành chuỗi C không làm cho cuộc sống của bạn khó khăn hơn, nhưng để bảo vệ mã của bạn khỏi nhiều lỗi không rõ ràng có thể gây ra do chuyển đổi ngầm không mong muốn. Tôi sẽ suy nghĩ rất lâu và khó về việc triển khai chúng. Chỉ cần suy nghĩ về điều này: Nó sẽ đưa bạn thêm một vài khoảnh khắc để gõ .c_str() một lần khi bạn viết mã, và cho phần còn lại của bất cứ ai đọc mã của bạn sẽ ngay lập tức biết rằng nó đang được sử dụng như một chuỗi kiểu C và không phải là một std::string.

Để trả lời câu hỏi của bạn, chỉ cần đặt mã trong tiêu đề:

//! Converts a value of the given type to a string. 
template <class _ValTy> static String ConvertFrom(_ValTy val) 
{ 
    // Code here 
} 

Cuối cùng lưu ý rằng mã nhận dạng bắt đầu với dấu gạch dưới + chữ cái viết hoa (và nhiều thứ khác bắt đầu với _) được dành riêng cho trình biên dịch và do đó tất cả các phiên cược sẽ bị tắt theo chức năng của chương trình.

+1

+1 Để trả lời câu hỏi và cho tôi một số lời khuyên tiết kiệm thời gian. Cảm ơn bạn. –

2

Định nghĩa chức năng của bạn hợp lệ và không thể xác định nó bên ngoài khai báo lớp theo cách ít tiết. Vì bạn muốn đặt định nghĩa hàm trong tệp .cpp, bạn không thể tận dụng lợi thế của việc kết hợp định nghĩa hàm với khai báo hàm ngắn gọn hơn. Bằng cách đặt định nghĩa hàm vào một tệp .cpp, bạn cũng sẽ phải khởi tạo một cách rõ ràng tất cả các chuyên môn cần thiết của lớp mẫu của bạn.

13

Cú pháp của quy định chức năng template thành viên bên ngoài của mẫu là như thế này:

template <class T> struct A 
{ 
    template <class X> void f(); 
}; 

template<class T> template<class X> void A<T>::f() 
{ 
} 

Vì vậy, mã của bạn là chính xác.

Xin lưu ý rằng việc xác định thành viên mẫu trong .cpp không phải là rất hữu ích. Trong trường hợp này, bạn sẽ nhanh chóng khởi tạo chúng với tất cả các loại mà bạn cần sử dụng với mẫu này. Hoặc không sử dụng chúng bên ngoài .cpp không có ý nghĩa.

+0

^cảm ơn bạn! Bạn đã cứu mạng tôi :) –

+0

@MathuSumMut Tốt để biết :-) – Rost