6

I'm wondering if there is any way to restrict generating code for a template using custom conditions in my case i want to function foo to be called only if template class T has inherieted by class bar(something like this)

template <class T:public bar> void foo()
{
    // do something
}
Ali1S232
  • 3,373
  • 2
  • 27
  • 46

2 Answers2

9

You can restrict T though using "Substitution Failure Is Not An Error" (SFINAE):

template <typename T>
typename std::enable_if<std::is_base_of<bar, T>::value>::type foo()
{

}

If T is not derived from bar, specialization of the function template will fail and it will not be considered during overload resolution. std::enable_if and std::is_base_of are new components of the C++ Standard Library added in the forthcoming revision, C++0x. If your compiler/Standard Library implementation don't yet support them, you can also find them in C++ TR1 or Boost.TypeTraits.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • Indeed, or if your `std` library doesn't have `is_base_of`, it's in Boost. – John Zwinck Apr 21 '11 at 23:20
  • Yep. The Boost equivalent would be `boost::enable_if >::type`; the `std::enable_if` takes a `bool` as its first argument whereas `boost::enable_if` takes a type. `std::enable_if` is equivalent to `boost::enable_if_c`. – James McNellis Apr 21 '11 at 23:24
  • do you have any idea how is the std library itself implemented enable_if or is_base_of classes? – Ali1S232 Apr 21 '11 at 23:28
  • There's a good answer to another question here on Stack Overflow that [explains how `is_base_of`](http://stackoverflow.com/questions/2910979/how-is-base-of-works/2913870#2913870) works. `enable_if` is trivial: you can take a look at [the Boost `enable_if_c` implementation](http://www.boost.org/doc/libs/1_46_1/boost/utility/enable_if.hpp) (It's the first two class definitions in that file; that's all there is to it. It defines a `::type` if the condition is true and it doesn't define it if the condition is false; that way, if the condition is false, the template can't be instantiated.). – James McNellis Apr 21 '11 at 23:30
  • Using return type for SFINAE is great! But in case of constructors it can't be used. I found that there's another trick, a dummy parameter with default value can be used instead, i.e. constructor_name(int normal_arg, typename std::enable_if::value>::type* dummy = 0). – queen3 Feb 01 '12 at 19:46
0

Yes, following technique can be used (for public inheritance). It will cause an overhead of just one pointer initialization.

Edit: Re-writing

template<typename Parent, typename Child>
struct IsParentChild
{
  static Parent* Check (Child *p) { return p; }
  Parent* (*t_)(Child*);
  IsParentChild() : t_(&Check) {} // function instantiation only
};

template<typename T>
void foo ()
{
  IsParentChild<Bar, T> check;
// ...
}
iammilind
  • 68,093
  • 33
  • 169
  • 336