MOHRE
MOHRE

Reputation: 1156

Enable_if as template parameter

Please tell me why this answer works.

  1. What happened to the enable_if such we can omit it after that? (further usage of Foo struct doesn't need that enable_if in template parameters)
  2. Should not that code be something like this:

Origin version:

template <typename Policy,
          typename = typename std::enable_if<std::is_base_of<BasePolicy, Policy>::value>::type >
struct Foo;

template <typename Policy>
struct Foo {
    Foo();
};

template <typename Policy>
Foo<Policy>::Foo() {
}

Edited version:

template <typename Policy,
          typename = typename std::enable_if<std::is_base_of<BasePolicy, Policy>::value>::type >
struct Foo;

template <typename Policy>
struct Foo<Policy> {  // <Policy> added!
    Foo();
};

template <typename Policy>
Foo<Policy>::Foo() {
}

Upvotes: 2

Views: 756

Answers (1)

Vittorio Romeo
Vittorio Romeo

Reputation: 93274

This happened:

  1. The author posted working code (<Policy> was present);

  2. There was some discussion in the comments that led the author to edit the code, and he made a mistake (<Policy> was removed);

  3. I rectified the mistake putting back the missing <Policy>.


Can anybody explains why even the edited version works?

When you attempt to instantiate Foo<T>, the declaration with the default template parameters is taken into account by the compiler. The default parameter is evaluated and if std::is_base_of<BasePolicy, Policy>::value is false then enable_if produces a SFINAE-friendly error.

If std::is_base_of<BasePolicy, Policy>::value is true, the partial specialization is chosen.

template <typename Policy>
struct Foo<Policy> {
    Foo() { } 
};

// is equivalent to

template <typename Policy>
struct Foo<Policy, void> {
    Foo() { } 
};

The above specializations are equivalent because typename std::enable_if<true>::type is void by default.

Upvotes: 3

Related Questions