2

I want to disallow instantiating a class template (PointCloud) for types with particular type traits. In the following example, I want to only allow types with is_good defined to be used:

#include <boost/core/enable_if.hpp>

class PointType1 {};

class PointType2 {};


template <typename T>
struct is_good
{
  static const bool value = false;
};

template <>
struct is_good<PointType1>
{
  static const bool value = true;
};

template <typename TPoint, typename boost::enable_if_c<is_good<TPoint>::value>::type = 0>
class PointCloud
{
};


int main()
{
  PointCloud<PointType1> pointCloud1;

  //PointCloud<PointType2> pointCloud2;

  return 0;
}

The error is:

error: 'boost::enable_if_c<true, void>::type {aka void}' is not a valid type for a template non-type parameter
   PointCloud<PointType1> pointCloud1;
                        ^

From my understanding, enable_if_c is supposed to define ::type to be TPoint if is_good<TPoint>::value is true. If it is false, then ::type is not defined, so the SFINAE should kick in. I also thought the typename would be indicating that this is indeed a type parameter.

Can anyone explain why this is happening?

Praetorian
  • 100,267
  • 15
  • 224
  • 307
David Doria
  • 8,881
  • 14
  • 75
  • 133

1 Answers1

3

When you instantiate PointCloud<PointType1>, is_good<TPoint>::value is true and boost::enable_if_c<is_good<TPoint>::value>::type is void.

As the error message says, void is not a valid type for a non-type template parameter.

To fix the error, specify the second type argument for enable_if_c instead of using the default argument void

template <typename TPoint,
          typename boost::enable_if_c<is_good<TPoint>::value, int>::type = 0>
                                                            ^^^^^
Praetorian
  • 100,267
  • 15
  • 224
  • 307
  • But this IS a type template parameter, no? Like isn't `2` a non-type template parameter, but `typedef anything` is a type template parameter? I guess I also don't understand the =0 at the end here - in a function template this just makes the argument a dummy argument when you pass nothing to it and the function doesn't get added to the overload set, but for a class template what does it mean to default the template argument to 0? – David Doria Jan 19 '16 at 22:18
  • 1
    @David No, that's a non type parameter. The `typename` there is because the `::type` is dependent on `TPoint` (see [this](http://stackoverflow.com/q/610245/241631)), so you need to tell the compiler it's a dependent name. `= 0` is a default template argument, just like with a default argument for a function parameter, it means you don't necessarily have to specify the template argument when instantiating the class. – Praetorian Jan 19 '16 at 22:58
  • So why is it a non type parameter? It evaluates to 'int' in your example case, which is a type, right? – David Doria Jan 19 '16 at 23:03
  • @DavidDoria Yes, but it's not an unbounded set of possible types, like `template` is. If you write `template`, then `N` is a non-type template parameter. Not sure how it gets that name, but maybe it's because the other kind are *type template parameters* – Praetorian Jan 20 '16 at 00:17