How to make sure that the template parameter is a subtype of the required type?

I have a template class, I want to do the following

  • Make sure that the object is created only if the passed template parameter is a subtype of the desired type
  • Communicate with the user of the code before the template parameter must satisfy

(1) is automatically considered in the sense that if the passed parameter of the template does not support some function that the class uses, the code will not compile. But this error can be detected quite late. I want the checks as early as possible. What I also want to do is that it should be obvious that the template parameter passed must be derived from the base type that I am providing.

Firstly, is it wrong? and if not, how can I do this? (simplest way please, C ++ is still new to me)

Thanks to stackoverflow, you really accelerated my C ++ learning speed.

+17
c ++ templates
Aug 11 '11 at 2:50
source share
3 answers

Given some complete MyBase type, the following will result in a compile-time error if T not obtained from MyBase :

 #include <boost/type_traits/is_base_of.hpp> #include <boost/static_assert.hpp> template<typename T> class Foo { BOOST_STATIC_ASSERT_MSG( (boost::is_base_of<MyBase, T>::value), "T must be a descendant of MyBase" ); // Foo implementation as normal }; 

If you use the C ++ 03 compiler with TR1, you can use std::tr1::is_base_of instead of boost::is_base_of ; if you use the C ++ 11 compiler, you can use std::is_base_of instead of boost::is_base_of and the boost::is_base_of keyword instead of the BOOST_STATIC_ASSERT_MSG macro:

 #include <type_traits> template<typename T> class Foo { static_assert( std::is_base_of<MyBase, T>::value, "T must be a descendant of MyBase" ); // Foo implementation as normal }; 

Nb this will give true_type for private and ambiguous derived types, so this is not enough if you really need to treat T as-a MyBase (in most contexts).

Doc links:
Boost StaticAssert
Boost Typetraits

+39
Aug 11 2018-11-11T00:
source share

From "Modern C ++ Design", chapter 2.7 ("Detecting convertibility and inheritance at compile time"): you can use the sizeof trick:

 typedef char Small; class Big { char dummy[2]; }; Small Test(Base1); Big Test(...); const bool isSubclassOfBase1 = sizeof(Test(Derived1())) == sizeof(Small); 

It exploits the fact that sizeof(...) can determine the type that the expression evaluates to, and since the return value has different sizes, the == check evaluates to true or false. If Derived1 is indeed Base1, the Small Test(Base1); overload is selected Small Test(Base1); and will be isSubclassOfBase1 .

Expanding from this, you can encapsulate the check and make a static statement so that it does not run at compile time:

 #include <boost/static_assert.hpp> class A {}; class B: public A {}; class C {}; template<class Base, class Derived> struct SubclassCheck { typedef char Yes; class No { char dummy[2]; }; static Yes Test(Base); static No Test(...); enum { Value = (sizeof(Test(*(Derived*)NULL)) == sizeof(Yes)) }; }; #define CHECK_DERIVES(b,d)\ BOOST_STATIC_ASSERT((SubclassCheck<b,d>::Value)); int main() { CHECK_DERIVES(A, B); // CHECK_DERIVES(A, C); // fails } 

You can use any other static implementation of the statement, not necessarily Boost.

+1
Aug 11 '11 at 3:01
source share

Yes, this is automatically taken if the parameter does not support what you are doing with it, this will lead to a compilation error. Manual validation if a type is a subtype of another type can only be performed (AFAIK) at run time, which is much later than compilation time. I do not know what you mean by this error, which is discovered late, the compilation time has already been reached. In addition, if everyone checked the type of parameters of their template, STL could not work with pointers, as well as with actual class-based iterators, and would not be nearly as flexible.

As for your user to know the requirements, just specify them in the documentation.

0
Aug 11 2018-11-11T00:
source share



All Articles