Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I create a compile time assertion that a template is of specific types?

I have a template function and wish to ensure at compile time that it is not instantiated on a subtype or supertype of a particular class.

How can I cause a C++ compiler error if this is violated?

class base {
};
class derived : public base {
};
class lowest : public derived {
};

template <typename T>
bool isCorrect(const T& obj) {
  typedef foo<T> D;
  foo<T> *def = foo<T>::find();
  return (def && def->getAnswer(object));
}

I want isCorrect to only be available for class derived, but not base or lowest. Note there could be many other lowest classes and a string of base classes to be excluded as well as alternative derived classes that are acceptable.

Is there a way in C++ to limit the template to only apply to the derived classes I explicitly specify?

like image 668
WilliamKF Avatar asked Dec 15 '11 00:12

WilliamKF


2 Answers

Type traits, specifically is_base_of.

#include <type_traits>

template <typename T>
bool isCorrect(const T& obj) {
  static bool const is_base = std::is_base_of<base, T>::value;
  static bool const derives = std::is_base_of<derived, T>::value;
  // specify allowed types here
  static bool const is_derived = std::is_same<T, derived>::value;
  // ---
  static_assert((!is_base && !derives) || is_derived, "wrong argument type");

  typedef foo<T> D;
  foo<T> *def = foo<T>::find();
  return (def && def->getAnswer(object));
}

Note that this is C++11 specific, but you can get the same behaviour with Boost.TypeTraits.

like image 54
Xeo Avatar answered Oct 06 '22 20:10

Xeo


Here's one technique that I know of.

First, make another template class policy_enforcer. Declare this class without defining it, and also provide a specialization of it for derived that is also defined:

template<typename T> struct policy_enforcer;
template<> struct policy_enforcer<derived> { };

Then, within the function you wish to lock down, include the expression sizeof(policy_enforcer<T>). Since sizeof on incomplete types is a compilation error, this will prevent the code from compiling.

Updated with live code: using base, using derived, using lowest.

like image 45
Jon Avatar answered Oct 06 '22 18:10

Jon