Member function check: Implement compile-time checks using C ++ 11 functions

I read that C ++ 11 has enough static validation (compilation time) to implement most of what should have been a validation of C ++ 11 concepts (deleted). (I read this in the comments on a recent question about concepts deleted ... - this question was quickly closed as not constructive).

The C ++ 03 code below checks for the presence of a member function in the class (on which my template class wants to work). Here are four member functions that are searched, and I always use the same template:

  • typedef to define the typedef of the function prototype
  • a static_cast call that breaks the compilation if ever a type name TExtension does not define such a member function, or if it has another prototype

Here is the code:

template <typename TExtension> class { ... void checkTemplateConcept() { typedef unsigned long (TExtension::*memberfunctionRequestedId)(); static_cast<memberfunctionRequestedId>(&TExtension::getRequestId); typedef eDirection (TExtension::*memberfunctionDirection)(); static_cast<memberfunctionDirection>(&TExtension::getDirection); typedef eDriveWay (TExtension::*memberfunctionDriveWay)(); static_cast<memberfunctionDriveWay>(&TExtension::getDriveWay); typedef unsigned long (TExtension::*memberfunctionCycleId)(); static_cast<memberfunctionCycleId>(&TExtension::getCycleId); } } 

This was in some part of my code, but it was completely based on C ++ 03 . I would gladly rewrite it with these new features in C ++ 11 ... what should I use here?

+4
source share
2 answers

With C ++ 11, you can get the compiler to print good error messages with static_assert like:

 typedef unsigned long (TExtension::*required_type)(); typedef decltype(&TExtension::getRequestId) actual_type; static_assert(std::is_same<required_type, actual_type>::value, "The type of getRequestId must be unsigned long (C::*)()"); 

Now, if the type of the member function does not match, the compiler will print this useful message:

 "The type of getRequestId must be unsigned long (C::*)()" 

You can make it more visual if you want. :-)

+6
source

Yes, in C ++ 11, SFINAE has been expanded to expressions, so you can define a trait such as is_t_extension to detect the presence of member functions, for example:

 template<class... T> struct holder { typedef void type; }; template<class T, class=void> struct is_t_extension : std::false_type {}; template<class T, class=void> struct is_t_extension<T, typename holder< decltype(std::declval<T>().getRequestId), decltype(std::declval<T>().getDirection), decltype(std::declval<T>().getDriveWay), decltype(std::declval<T>().getCycleId) >::type> : std::true_type {}; 

Now it just checks their presence. With some work, you could extend the above to discover valid signatures, or you could use the Tick library to write a lot of clean characters instead:

 TICK_TRAIT(is_t_extenstion) { template<class T> auto requires_(T&& x) -> TICK_VALID( returns<unsigned long>(x.getRequestId), returns<eDirection>(x.getDirection), returns<eDriveWay>(x.getDriveWay), returns<unsigned long>(x.getCycleId) ); }; 

Then in your class, you can simply use static_assert to report an error:

 template <typename TExtension> class foo { static_assert(is_t_extension<TExtension>(), "Not a TExtension"); }; 

Or, if you want to enable specialization, you can use TICK_CLASS_REQUIRES :

 template <typename TExtension, class=void> class foo; template <typename TExtension> class foo<TExtension, TICK_CLASS_REQUIRES(is_t_extension<TExtension>())> { ... }; 
0
source

All Articles