Jake
Jake

Reputation: 7773

Writing custom c++14-style type aliases

I wanted to create a _t alias for std::is_base_of, similar to how std::enable_if_t is an alias for std::enable_if. So I added the following to my standard header:

namespace std {
  template<typename T, typename U>
  using is_base_of_t = typename is_base_of<T,U>::type;
}

I'm using this new alias in the following context:

template <typename SpaceT,
          typename TagT,
          typename = std::enable_if_t<std::is_base_of_t<Space,SpaceT>>>
class SpatialTree : public SpaceT {
};

And I'm getting the following gcc error:

SpatialTree.h:48:101: error: type/value mismatch at argument 1 in template parameter list for ‘template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type’
 template <typename SpaceT, typename TagT, typename = std::enable_if_t<std::is_base_of_t<Space,SpaceT>>>

What am I doing wrong?

Upvotes: 1

Views: 549

Answers (3)

TemplateRex
TemplateRex

Reputation: 70526

Available already as of Clang 3.6 and g++ 5.1

#include <experimental/type_traits>

using namespace std::experimental;

struct B {}; struct D : B {};

int main() 
{
    static_assert(is_base_of_v<B, D>, "");
}

Upvotes: 2

Barry
Barry

Reputation: 302892

std::enable_if is defined thusly:

template< bool B, class T = void >
struct enable_if;

The first argument is a value, not a type. You need to pass in std::is_base_of<Space,SpaceT>::value as the first argument. With C++14, the correct alias would be a variable template:

template <class Base, class Derived>
constexpr bool is_base_of_v = std::is_base_of<Base, Derived>::value;

that you'd use the same way:

template <typename SpaceT, typename TagT,
          typename = std::enable_if_t<is_base_of_v<Space,SpaceT>>>
                                                ^^^
class SpatialTree : public SpaceT {
};

The latter currently exists in <experimental/type_traits>.

Upvotes: 5

Columbo
Columbo

Reputation: 60979

enable_if[_t] wants a bool as its first argument. You have to write std::enable_if_t<std::is_base_of_t<Space,SpaceT>::value> or std::enable_if_t<std::is_base_of_t<Space,SpaceT>{}>, otherwise you pass a type where a bool is required.

However, you might want to define a counterpart of std::experimental::is_base_of_v instead:

template <class Base, class Derived>
constexpr bool is_base_of_v = std::is_base_of<Base, Derived>{};

and use as std::enable_if_t<is_base_of_v<Space, SpaceT>>.

That said, I wouldn't define either of these templates in namespace std, since that invokes UB as per [namespace.std]/1.

Upvotes: 3

Related Questions