Why would a template class have an unused type?

boost-units, c++, generic-programming, template-classes, templates

Solution

That class template is forward declared in `"units_fwd.hpp"`.

template<class Dim,class System, class Enable=void> class unit;

there we see that the 3rd parameter is defaulted to `void`. I would be tempted to even do `template<class Dim,class System, class=void> class unit;` and also leave it nameless in the implementation, but there may be compiler compatibility or code standards that mean they give it the name `Enable`.

Such an "extra" type allows for SFINAE tests on the first two types. If you create a specialization where the 3rd type is only valid for some subsets of `Dim` and `System` the extra parameter (defaulted to `void`) lets you do that.

You can even leave your base implementation empty (either `;` or `{};` which have different effects) and only specialize, making arguments that fail your test be treated as invalid options.

Here is a toy example of SFINAE:

template<class T, class=void> struct is_int : std::false_type {};
template<class T> struct is_int< T,
  std::enable_if_t< std::is_same<T, int>{} >
> : std::true_type {};

the base specialization inherits from `false_type`. If, however, the type `T` passes my test in the next specialization, it is preferred, and the result inherits from `true_type`.

In this case, we'd be better served by just doing `is_int< int, void >:std::true_type{}`, but in a more complex situation (say, `is_integral`) we can do a nearly arbitrary compile-time check and use it to enable or disable the `true_type` specialization.

Problem

I'm reviewing the boost units library and I am puzzled why the boost::units::unit class has an extra template parameter. Here is the example: http://www.boost.org/doc/libs/1_57_0/boost/units/unit.hpp ``` template<class Dim,class System, class Enable> class unit { public: typedef unit<Dim, System> unit_type; typedef unit<Dim,System> this_type; typedef Dim dimension_type; typedef System system_type; unit() { } unit(const this_type&) { } //~unit() { } this_type& operator=(const this_type&) { return *this; } // sun will ignore errors resulting from templates // instantiated in the return type of a function. // Make sure that we get an error anyway by putting. // the check in the destructor. #ifdef __SUNPRO_CC ~unit() { BOOST_MPL_ASSERT((detail::check_system<System, Dim>)); BOOST_MPL_ASSERT((is_dimension_list<Dim>)); } #else private: BOOST_MPL_ASSERT((detail::check_system<System, Dim>)); BOOST_MPL_ASSERT((is_dimension_list<Dim>)); #endif }; ``` The class is used to add dimensions to dimension system. ``` typedef unit<pressure_dimension,si::system> pressure; ``` What purpose would "Enable" serve in this case?

Original source