chchchch
chchchch

Reputation: 11

Nested template class with std::enable_if, C++

I have a template class B whose first parameter T1 must inherit class A, and second parameter T2 is used in nested class C:

class A { ... };

template<typename T1, typename T2 = T1, typename = std::enable_if_t<std::is_base_of<A, T1>::value>>
class B {
    class C {
        T2 data;

        C(T2 data);
        void func();

        ...
    };

    ...
};

The problem is that I get errors when I try to define constructor and methods of nested class:

template<typename T1, typename T2, typename>
B<T1, T2>::C::C(T2 data) : data(data) { ... }

template<typename T1, typename T2, typename>
void B<T1, T2>::C::func() { ... }
  1. E0464 "B<T1, T2, std::enable_if_t<std::is_base_of<A, T1>::value, void>>::C" is not a class template;
  2. C3860 type argument list following class type name must list parameters in the order used in type parameter list.

Code works fine if I dont use nested class or dont use std::enable_if, but here I need them both and I dont really understand what is wrong.

Upvotes: 0

Views: 143

Answers (1)

Jan Schultke
Jan Schultke

Reputation: 39424

You still have to provide the defaulted template parameter when defining the constructor:

template<typename T1, typename T2, typename D>
B<T1, T2, D>::C::C(T2 data) : data(data) { }

Note that you would be way better off defining the constructor inside C. You can't split templates into header/source most of the time anyway, and dealing with out-of-line definitions of class templates can be very annoying and fragile.

Note on C++17 and C++20

If you were using C++20, you could write:

template<std::derived_from<A> T1, typename T2 = T1>
class B { /* ... */ };

template<std::derived_from<A> T1, typename T2>
B<T1, T2>::C::C(T2 data) : data(data) { }

If you were using C++17, you could at least use the helper variable template std::is_base_of_v<A, T1>.

Upvotes: 0

Related Questions