chuyên môn hóa rõ ràng của chức năng thành viên lớp mẫu


88

Tôi cần chuyên biệt hóa chức năng thành viên mẫu cho một số loại (giả sử đôi ). Nó hoạt động tốt trong khi Xbản thân lớp không phải là lớp mẫu, nhưng khi tôi làm cho nó mẫu thì GCC bắt đầu đưa ra lỗi thời gian biên dịch.

#include <iostream>
#include <cmath>

template <class C> class X
{
public:
   template <class T> void get_as();
};

template <class C>
void X<C>::get_as<double>()
{

}

int main()
{
   X<int> x;
   x.get_as();
}

đây là thông báo lỗi

source.cpp:11:27: error: template-id
  'get_as<double>' in declaration of primary template
source.cpp:11:6: error: prototype for
  'void X<C>::get_as()' does not match any in class 'X<C>'
source.cpp:7:35: error: candidate is:
  template<class C> template<class T> void X::get_as()

Làm thế nào tôi có thể khắc phục điều đó và vấn đề ở đây là gì?

Cảm ơn trước.


2
điều này là bất hợp pháp trong tiêu chuẩn hiện tại, để chuyên môn hóa, bạn cũng phải chuyên môn hóa lớp học ...
Nim

nhưng nó hoạt động nếu lớp không phải là mẫu. Nó có bất hợp pháp quá không?
ledokol

không, điều đó hoàn toàn ổn, nó chỉ dành cho các mẫu lớp áp dụng quy tắc này (AFAIK).
Nim

Câu trả lời:


108

Nó không hoạt động theo cách đó. Bạn cần phải nói những điều sau đây, nhưng nó không chính xác

template <class C> template<>
void X<C>::get_as<double>()
{

}

Các thành viên chuyên biệt rõ ràng cũng cần các mẫu lớp xung quanh của họ cũng được chuyên biệt rõ ràng. Vì vậy, bạn cần phải nói những điều sau đây, điều này sẽ chỉ chuyên biệt cho thành viên X<int>.

template <> template<>
void X<int>::get_as<double>()
{

}

Nếu bạn muốn giữ cho mẫu xung quanh không chuyên biệt, bạn có một số lựa chọn. Tôi thích quá tải

template <class C> class X
{
   template<typename T> struct type { };

public:
   template <class T> void get_as() {
     get_as(type<T>());
   }

private:
   template<typename T> void get_as(type<T>) {

   }

   void get_as(type<double>) {

   }
};

tại sao bạn cần type<>trình bao bọc? không thể đúc một kiểu từ 0 đến một con trỏ loại Tlàm thủ thuật? Tôi đoán nó không thanh lịch bằng ...
Nim

Có vẻ như điều này thực sự không thể làm được. Cảm ơn.
ledokol

3
@Nim phải, tôi nghĩ rằng con trỏ cast thứ là xấu xí và sẽ không hoạt động cho các loại bạn không thể tạo con trỏ đến (tham chiếu). Ngoài ra, có một tham số hàm là một con trỏ đến một kiểu mảng không có kích thước là bất hợp pháp trong C ++. Có nó trong một trình bao bọc loại làm cho nó hoạt động cho tất cả các loại.
Johannes Schaub - litb

2
@ JohannesSchaub-litb: Các lựa chọn khác cùng với quá tải là gì? Có thể hiển thị một số trong số họ?
Jean-Bernard Jansen

2
@ phản xạ nhanh bình luận của anh ấy là dùng template<typename T> void get_as(T*); void get_as(double*);và vượt qua a (T*)0.
Johannes Schaub - litb

24

Nếu một người có thể sử dụng, std::enable_ifchúng tôi có thể dựa vào SFINAE (lỗi thay thế không phải là một lỗi)

điều đó sẽ hoạt động như vậy (xem TRỰC TIẾP ):

#include <iostream>
#include <type_traits>

template <typename C> class X
{
public:
    template <typename T, 
              std::enable_if_t<!std::is_same_v<double,T>, int> = 0> 
    void get_as() { std::cout << "get as T" << std::endl; }

    template <typename T, 
              std::enable_if_t<std::is_same_v<double,T>, int> = 0> 
    void get_as() { std::cout << "get as double" << std::endl; }
};

int main() {
   X<int> d;
   d.get_as<double>();

   return 0;
}

Điều tồi tệ là, với tất cả các chuyên môn của enable_if này, chỉ cần có một chuyên môn cho trình biên dịch, nếu không sẽ phát sinh lỗi định dạng. Đó là lý do tại sao hành vi mặc định "get as T" cũng cần kích hoạt nếu.


Đã cập nhật bài đăng để làm cho nó hiện đại hơn.
Gabriel
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.