147

Suppose I have a template function and two classes

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

How do I do the check for T is animal? I don't want to have something that checks during the run time. Thanks

0

6 Answers 6

199

Use is_same:

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

Usually, that's a totally unworkable design, though, and you really want to specialize:

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

Note also that it's unusual to have function templates with explicit (non-deduced) arguments. It's not unheard of, but often there are better approaches.

Sign up to request clarification or add additional context in comments.

14 Comments

TThanks! Actually they share A LOT of code so I can not really duplicate it
@WhatABeautifulWorld: You can always factor your code so that the type-dependent part can be relegated to a specializable function...
One quick follow-up, if I do use std::is_same, then it will NOT slow down the code for other template parameters, right?
@WhatABeautifulWorld: The trait values are all statically known. There shouldn't be any runtime cost, provided your compiler is half-decent. Check the assembly if in doubt, though.
@AdriC.S.: Since T isn't deduced, there's not much you can do. You could leave the primary template unimplemented and create a specialization, or you could add a static assertion with is_same.
|
71

I think todays, it is better to use, but this only works with C++17 or later.

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

If you use some type specific operations in if expression body without constexpr, this code will not compile.

4 Comments

could you elaborate on why this is better? is it performance or platform related?
Actually works. Ty!
@serup it's better, because it is new, and old things are always worse. inline constexpr bool is_same_v = is_same<T, U>::value; I have no clue why they keep adding these pointless "helpers" which only confuse people instead of fixing their broken language.
@user1187719 "old things are always worse" extremely questionable statement
13

std::is_same() is only available since C++11. For pre-C++11 you can use typeid():

template <typename T> void foo() { if (typeid(T) == typeid(animal)) { /* ... */ } } 

Comments

10

You can specialize your templates based on what's passed into their parameters like this:

template <> void foo<animal> { } 

Note that this creates an entirely new function based on the type that's passed as T. This is usually preferable as it reduces clutter and is essentially the reason we have templates in the first place.

2 Comments

Hmm. Is this method really the only preferable way to specialize template argument? Let's say I've 10 different child classes that I need to manage inside the template function. Do I really have to write 10 different template functions for respective class? I think I may be missing the core point here.
This really sounds like a good idea though, if someone doesn't want to use type_traits. Like someone mentioned the main logic can be done in a different function, which accepts an extra flag to indicate the type, and this specialized declaration can just set the flag accordingly and directly pass on all the other arguments without touching anything. So if 10 different classes need to be handled, it is basically 10 lines for 10 different function definitions. But this will get a lot complicated if there are more than 1 template variable.
7

In C++17, we can use variants.

To use std::variant, you need to include the header:

#include <variant> 

After that, you may add std::variant in your code like this:

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... } } 

3 Comments

How are T and Type connected?
This answer is problematic in several ways. Besides the actual errors (type which is the value of type Type or a template which does not make sense here) is_same_v is not meaningful in the context of variant. The corresponding "trait" is holds_alternative.
std::variant is totally unnecessary here
2

use c++ concepts https://en.cppreference.com/w/cpp/language/constraints

for example class who recive only char types

#include <concepts> template<typename Type> concept CharTypes = std::is_same<Type, char>::value || std::is_same<Type, wchar_t>::value || std::is_same<Type, char8_t>::value || std::is_same<Type, char16_t>::value || std::is_same<Type, char32_t>::value; template<CharTypes T> class Some{}; 

and yes, this not working

 Some<int> s; 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.