Làm cách nào để kiểm tra loại tham số mẫu?


92

Giả sử tôi có một hàm mẫu và hai lớp

class animal {
}
class person {
}

template<class T>
void foo() {
  if (T is animal) {
    kill();
  }
}

Làm cách nào để kiểm tra T là động vật? Tôi không muốn có thứ gì đó kiểm tra trong thời gian chạy. Cảm ơn


55
Tôi sẽ đặt "pet" thay vì "kill" :-)
JimBamFeng

Câu trả lời:


130

Sử dụng is_same:

#include <type_traits>

template <typename T>
void foo()
{
    if (std::is_same<T, animal>::value) { /* ... */ }  // optimizable...
}

Thông thường, đó là một thiết kế hoàn toàn không thể thực hiện được và bạn thực sự muốn chuyên môn hóa :

template <typename T> void foo() { /* generic implementation  */ }

template <> void foo<animal>()   { /* specific for T = animal */ }

Cũng lưu ý rằng thật bất thường khi có các mẫu hàm với các đối số rõ ràng (không được suy luận). Nó không phải là chưa từng thấy, nhưng thường có những cách tiếp cận tốt hơn.


2
Xin cảm ơn! Trên thực tế họ chia sẻ rất nhiều mã để tôi có thể không thực sự trùng lặp nó
WhatABeautifulWorld

3
@WhatABeautifulWorld: Bạn luôn có thể yếu tố mã của bạn để phần loại phụ thuộc có thể được chuyển xuống một hàm specializable ...
Kerrek SB

1
Một lần theo dõi nhanh, nếu tôi sử dụng std :: is_same, thì nó sẽ KHÔNG làm chậm mã cho các tham số mẫu khác, phải không?
WhatABeautifulWorld, 30/11/12

1
@WhatABeautifulWorld: Các giá trị đặc điểm đều được biết ở dạng tĩnh. Sẽ không có bất kỳ chi phí thời gian chạy nào, miễn là trình biên dịch của bạn là một nửa. Tuy nhiên, hãy kiểm tra việc lắp ráp nếu nghi ngờ.
Kerrek SB,

2
@ AdriC.S: Vì Tkhông được suy luận nên bạn không thể làm gì nhiều. Bạn có thể để mẫu chính chưa hoàn thành và tạo một chuyên môn hóa hoặc bạn có thể thêm một xác nhận tĩnh với is_same.
Kerrek SB

34

Tôi nghĩ rằng ngày nay, tốt hơn là sử dụng, nhưng chỉ với C ++ 17.

#include <type_traits>

template <typename T>
void foo() {
    if constexpr (std::is_same_v<T, animal>) {
        // use type specific operations... 
    } 
}

Nếu bạn sử dụng một số thao tác cụ thể kiểu trong if nội dung biểu thức mà không có constexpr, mã này sẽ không biên dịch.


8
thay vì std::is_same<T, U>::valuebạn có thể sử dụng ngắn hơn:std::is_same_v<T, U>
Fureeish

9

Trong C ++ 17, chúng ta có thể sử dụng các biến thể .

Để sử dụng std::variant, bạn cần bao gồm tiêu đề:

#include <variant>

Sau đó, bạn có thể thêm std::variantmã của mình như sau:

using Type = std::variant<Animal, Person>;

template <class T>
void foo(Type type) {
    if (std::is_same_v<type, Animal>) {
        // Do stuff...
    } else {
        // Do stuff...
    }
}

8
T và Type được kết nối như thế nào?
mabraham 18/09/18

4
Câu trả lời này có vấn đề theo một số cách. Bên cạnh các lỗi thực tế ( typelà giá trị của kiểu Typehoặc mẫu không có ý nghĩa ở đây) is_same_vkhông có ý nghĩa trong ngữ cảnh của variant. "Đặc điểm" tương ứng là holds_alternative.
Pixelchemist

std::varianthoàn toàn không cần thiết ở đây
tjysdsg

7

Bạn có thể chuyên biệt hóa các mẫu của mình dựa trên những gì được truyền vào các tham số của chúng như sau:

template <> void foo<animal> {

}

Lưu ý rằng điều này tạo ra một hàm hoàn toàn mới dựa trên kiểu được truyền là T. Điều này thường thích hợp hơn vì nó làm giảm sự lộn xộn và về cơ bản là lý do chúng tôi có các mẫu ngay từ đầu.


Hừ! Phương pháp này có thực sự là cách thích hợp duy nhất để chuyên biệt hóa đối số mẫu không? Giả sử tôi có 10 lớp con khác nhau mà tôi cần quản lý bên trong hàm mẫu. Tôi có thực sự phải viết 10 hàm mẫu khác nhau cho lớp tương ứng không? Tôi nghĩ rằng tôi có thể thiếu điểm cốt lõi ở đây.
Volkan Güven

Điều này thực sự có vẻ là một ý tưởng hay, nếu ai đó không muốn sử dụng type_traits. Giống như ai đó đã đề cập, logic chính có thể được thực hiện trong một hàm khác, nó chấp nhận một cờ phụ để chỉ ra loại và khai báo chuyên biệt này có thể chỉ đặt cờ cho phù hợp và trực tiếp chuyển tất cả các đối số khác mà không cần chạm vào bất kỳ thứ gì. Vì vậy, nếu 10 lớp khác nhau cần được xử lý, về cơ bản nó là 10 dòng cho 10 định nghĩa chức năng khác nhau. Nhưng điều này sẽ trở nên phức tạp nếu có nhiều hơn 1 biến mẫu.
Harish Ganesan
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.