You really don't want to be doing this branching at runtime, with typeid
.
We want this code:
int main()
{
SMTH<int>().add();
SMTH<char>().add();
return 0;
}
To output:
int
not int
There are lot of ways I can think of to achieve this (all at compile time and half of them requires C++11):
Specialize the whole class (if it has only this add
function):
template <typename T>
struct SMTH
{
void add() { std::cout << "not int" << std::endl; }
};
template <>
struct SMTH<int>
{
void add() { std::cout << "int" << std::endl; };
};
Specialize only the add
member function (recommended by @Angelus):
template <typename T>
struct SMTH
{
void add() { std::cout << "not int" << std::endl; }
};
template <> // must be an explicit (full) specialization though
void SMTH<int>::add() { std::cout << "int" << std::endl; }
Note that if you instantiate SMTH
with cv-qualified int
, you'll get the not int
output for above approaches.
Use the SFINAE idiom. There are few variants of it (default template argument, default function argument, function return type), and the last one is the one that fits here:
template <typename T>
struct SMTH
{
template <typename U = T>
typename std::enable_if<!std::is_same<U, int>::value>::type // return type
add() { std::cout << "not int" << std::endl; }
template <typename U = T>
typename std::enable_if<std::is_same<U, int>::value>::type
add() { std::cout << "int" << std::endl; }
};
The main benefit is that you can make the enabling condition complex, e.g. using std::remove_cv
to choose the same overload regardless of cv-qualifiers.
Tag dispatching - chooses the add_impl
overload based on if the instantiated tag inherits from A
or B
, in this case std::false_type
or std::true_type
. You still use template specialization or SFINAE, but this time it's done on a tag class:
template <typename>
struct is_int : std::false_type {};
// template specialization again, you can use SFINAE, too!
template <>
struct is_int<int> : std::true_type {};
template <typename T>
struct SMTH
{
void add() { add_impl(is_int<T>()); }
private:
void add_impl(std::false_type) { std::cout << "not int" << std::endl; }
void add_impl(std::true_type) { std::cout << "int" << std::endl; }
};
This can of course be done without defining the custom tag class, and the code in add
will look like this:
add_impl(std::is_same<T, int>());
I don't know if I mentioned them all, and I don't know why I attempted to, either. All you have to do now is to choose the one that fits the use the best.
Now, that I see, that you also wanted to check if a function exists. This is already long, and there's an existing QA about that.