9

Say I have a function with template type T and two other classes A and B.

template <typename T>
void func(const T & t)
{
    ...........
    //check if T == A do something
    ...........
    //check if T == B do some other thing
}

How can I do these two checks (without using Boost library)?

Narek
  • 38,779
  • 79
  • 233
  • 389

3 Answers3

10

If you literally just want a boolean to test whether T == A, then you can use is_same, available in C++11 as std::is_same, or prior to that in TR1 as std::tr1::is_same:

const bool T_is_A = std::is_same<T, A>::value;

You can trivially write this little class yourself:

template <typename, typename> struct is_same { static const bool value = false;};
template <typename T> struct is_same<T,T> { static const bool value = true;};

Often though you may find it more convenient to pack your branching code into separate classes or functions which you specialize for A and B, as that will give you a compile-time conditional. By contrast, checking if (T_is_A) can only be done at runtime.

Narek
  • 38,779
  • 79
  • 233
  • 389
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 1
    What do you mean, only done at runtime? `is_same::value` is an integer constant expression. Code in `if(T_is_A)` is likely to be subject to dead code removal in a decent compiler, that happens before runtime. The problem is that the code in both branches still has to compile before it's eliminated. – Steve Jessop Oct 04 '11 at 12:56
  • @SteveJessop: Well, that optimization is a detail... the main point is as you say, though, that all the branch code has to be valid code, which is quite a restriction. By contrast, specialized templates aren't required to make sense unless they're actually instantiated. – Kerrek SB Oct 04 '11 at 13:01
  • This solution has an advantage against already proposed ones, cause if "do something" and "do some other thing" were define a variable as a double and define a variable as int, the function specialization technic will not work as those variable would be local for those functions. Thanks for nice solution! – Narek Oct 05 '11 at 05:47
7

Create function templates with specializations, that will do the thing you want.

template <class T>
void doSomething() {}

template <>
void doSomething<A>() { /* actual code */ }

template <class T>
void doSomeOtherThing() {}

template <>
void doSomeOtherThing<B>() { /* actual code */ }

template <typename T>
void func(const T & t)
{
    ...........
    //check if T == A do something
    doSomething<T>();
    ...........
    //check if T == B do some other thing
    doSomeOtherThing<T>();
}
jpalecek
  • 47,058
  • 7
  • 102
  • 144
  • If you omit the definition of the primary template altogether, `template void doSomething();`, then you'll get a nice compile-time error if the type is neither `A` nor `B`. – Kerrek SB Oct 04 '11 at 12:51
  • @KerrekSB: Actually, in this case, you'd get a compile time error regardless of `T`, because the specialization would fail to find its primary template. That's why both are included :) – jpalecek Oct 04 '11 at 12:54
  • Indeed, you'd have to omit the general definition and add a do-nothing definition for `doSomething` and `doSomeOtherThing`. – Steve Jessop Oct 04 '11 at 12:58
  • Yeah, I misread the OP's question as a "switch" on `T`, but that's not actually what was asked for. Never mind :-S – Kerrek SB Oct 04 '11 at 13:00
  • @SteveJessop: why? I don't understand. – jpalecek Oct 04 '11 at 13:06
  • @jpalacek: you'd have to do that in order to get the effect Kerrek described, I mean. Although come to think of it, it might then be pointless using a template at all, an overloaded function for `A` and `B` would do assuming that the code left out by the questioner actually uses `t`. – Steve Jessop Oct 04 '11 at 13:07
  • 1
    @SteveJessop: Yes, but the semantics would be slightly different. It would need an actual `T` as argument (not a problem, OP probably wants to use it anyway) and it would specialize on `T`s that are not `A`, but are convertible to `T` (or `T&`, depends on how you do it). – jpalecek Oct 04 '11 at 13:11
  • Good point about conversion. Even if I use non-const `T&` for my overload, a type derived from `A` would convert, and so it's a matter of whether the questioner actually wants an exact type check (i.e. expects violation of LSP), or is happy for derived classes of `A` to behave like `A`. Probably if we stepped back far enough to answer that question, we'd come up with even more possible mechanisms. – Steve Jessop Oct 04 '11 at 13:17
3

If you want to have a special implementation of func for some parameter type, simply create an overload specific for that type:

template <typename T>
void func(const T & t) {
   // generic code
}

void func(const A & t) {
   // code for A
}
sth
  • 222,467
  • 53
  • 283
  • 367