Як перевірити тип параметра шаблону?


97

Припустимо, у мене є функція шаблону і два класи

class animal {
}
class person {
}

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

Як мені перевірити наявність тварини? Я не хочу мати щось, що перевіряє під час роботи. Дякую


61
Я б поставив "домашнього улюбленця" замість "вбити" :-)
JimBamFeng 02

Відповіді:


135

Використання is_same:

#include <type_traits>

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

Зазвичай це абсолютно непрацездатний дизайн, однак ви дуже хочете спеціалізуватися :

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

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

Також зауважте, що незвично мати шаблони функцій з явними (невиведеними) аргументами. Це не нечувано, але часто є кращі підходи.


2
Дякую! Насправді вони діляться БАГАТО коду, тому я не можу насправді дублювати його
WhatABeautifulWorld

3
@WhatABeautifulWorld: Ви завжди можете розкласти свій код на фактори, щоб залежну від типу частину можна було віднести до спеціалізованої функції ...
Kerrek SB

1
Одне швидке продовження, якщо я все-таки використовую std :: is_same, то це НЕ сповільнить код для інших параметрів шаблону, так?
WhatABeautifulWorld

1
@WhatABeautifulWorld: Усі ознаки статистично відомі. Не повинно бути ніяких витрат на виконання, за умови, що ваш компілятор напівпристойний. Перевірте монтаж, якщо у вас є сумніви.
Kerrek SB

2
@ AdriC.S .: Оскільки Tце не виведено, ви не можете багато чого зробити. Ви можете залишити основний шаблон нереалізованим і створити спеціалізацію, або можете додати статичне твердження за допомогою is_same.
Kerrek SB

37

Я думаю, сьогодні це краще використовувати, але тільки з C ++ 17.

#include <type_traits>

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

Якщо ви використовуєте певні операції типу в тілі виразу if constexpr, цей код не компілюється.


8
замість цього std::is_same<T, U>::valueви можете використати коротший:std::is_same_v<T, U>
Fureeish

12

У C ++ 17 ми можемо використовувати варіанти .

Для використання std::variantпотрібно включити заголовок:

#include <variant>

Після цього ви можете додати std::variantу свій код так:

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 і Type?
Мабрагам

4
Ця відповідь проблематична кількома способами. До того ж фактичні помилки ( typeщо є значенням типу Typeабо шаблону, який тут не має сенсу) is_same_vне мають сенсу в контексті variant. Відповідна "риса" є holds_alternative.
Піксельхімік,

std::variantтут абсолютно непотрібно
tjysdsg

7

Ви можете спеціалізувати свої шаблони на основі того, що передається в їх параметри, як це:

template <> void foo<animal> {

}

Зверніть увагу, що це створює абсолютно нову функцію на основі типу, який передається як T. Зазвичай це переважно, оскільки це зменшує безлад і, по суті, є причиною того, що ми маємо шаблони в першу чергу.


Хм Чи справді цей метод є єдиним кращим способом спеціалізації аргументу шаблону? Скажімо, у мене є 10 різних дочірніх класів, якими мені потрібно керувати всередині функції шаблону. Чи справді мені доводиться писати 10 різних функцій шаблону для відповідного класу? Я думаю, що я, можливо, тут не бачу сутності.
Volkan Güven

Це дійсно звучить як гарна ідея, якщо хтось не хоче використовувати type_traits. Як хтось згадав, основна логіка може бути виконана в іншій функції, яка приймає додатковий прапор для позначення типу, і ця спеціалізована декларація може просто встановити прапор відповідно і безпосередньо передавати всі інші аргументи, не торкаючись нічого. Отже, якщо потрібно обробляти 10 різних класів, це в основному 10 рядків для 10 різних визначень функцій. Але це значно ускладниться, якщо є більше 1 змінної шаблону.
Харіш Ганесан
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.