Switch passed type from template

23,647

Solution 1

Yes, it is...but it probably won't work the way you expect.

template < typename T >
void foo()
{
  if (is_same<T,SomeClass>::value) ...;
  else if (is_same<T,SomeClass2>::value) ...;
}

You can get is_same from std:: or boost:: depending on your desire/compiler. The former is only in C++0x.

The problem comes with what is in .... If you expect to be able to make some function call specific to those types within foo, you are sadly mistaken. A compiler error will result even though that section of code is never run when you pass in something that doesn't obey that expected interface.

To solve THAT problem you need to do something a bit different. I'd recommend tag dispatching:

struct v1_tag {};
struct v2_tag {};

template < typename T > struct someclass_version_tag;
template < > struct someclass_version_tag<SomeClass> { typedef v1_tag type; };
template < > struct someclass_version_tag<SomeClass2> { typedef v2_tag type; };

void foo(v1_tag) { ... }
void foo(v2_tag) { ... }
template < typename T > void foo()
{
  typedef typename someclass_version_tag<T>::type tag;
  foo(tag());
}

Note that you will not be suffering any runtime-polymorphism overhead here and with optimizations turned on it should result in the same or even smaller code size AND speed (though you shouldn't be worrying about that anyway until you've run a profiler).

Solution 2

If you want to do something specific based on the type, specialize the template:

template <typename T>
void Foo() { }

template <>
void Foo<SomeClass>() { }

template <> 
void Foo<SomeClass2>() { }

// etc.

(You don't actually want to specialize the function template, though; this is for exposition only. You'll either want to overload the template if you can, or delegate to a specialized class template. For more on why and how to avoid specializing function templates, read Herb Sutter's Why Not Specialize Function Templates?)

Solution 3

No, however you can use partial specialization :

template<typename T>
struct Bar { static void foo(); };
template<typename T>
template<> inline void Bar<T>::foo() {
//generic
}
template<> inline void Bar<int>::foo() {
//stuff for int
}
template<> inline void Bar<QString>::foo() {
//QString
}

Edit Yes with type traits, however it's not really needed. Edit 2 type_traits example.

#include <type_traits>
template<typename T> void foo() {
    using std::is_same;
    if<is_same<T, T2>::value || is_same<T, T1>::value) { 
        /* stuff */
    }
}
Share:
23,647
Hanut
Author by

Hanut

Updated on July 17, 2022

Comments

  • Hanut
    Hanut almost 2 years

    Is it possible in C++ to check the type passed into a template function? For example:

    template <typename T>
    void Foo()
    {
       if (typeof(SomeClass) == T)
          ...;
       else if (typeof(SomeClass2) == T)
          ...;
    }
    
  • Admin
    Admin over 13 years
    What if I want to do something like if (is_same<T, T1> || is_same<T, T2>)?
  • OneOfOne
    OneOfOne over 13 years
    Then you have to use type traits #include <type_traits> and std::is_same<T, T2>::value if your compiler supports C++0x (VS2010/any recent gcc) or just use boost for old compiler compatibility.
  • Edward Strange
    Edward Strange over 13 years
    That's not partial specialization, it's full specialization. There's a pretty significant difference. Probably most significant is that it would be impossible to do partial specialization that way since it's not allowed with functions of any sort.
  • Boying
    Boying about 7 years
    Is it possible to return different types based on version_tag?
  • Edward Strange
    Edward Strange about 7 years
    Sure. You need to come up with some way to query the information if you're stuck in C++03, or use auto in C++11 and up. So long as you don't try to return different types within the same instantiation you'll have no problem.
  • xaxxon
    xaxxon over 6 years
    now with C++17, you can use constexpr if statements to do this trivially