using Enable_if = typename ...">

Why the compiler said: "enable_if" cannot be used to disable this declaration

template <bool Cond, typename Type = void> using Enable_if = typename std::enable_if<Cond, Type>::type; class Degree; template <typename T> constexpr inline bool Is_Degree() { return std::is_base_of<Degree, T>::value; } class Degree { public: std::size_t inDeg = 0; }; template <typename Satellite = Degree> class Vertex: public Satellite { public: explicit Vertex(int num): n(num) {} private: std::size_t n; }; template <typename Satellite = Degree> class Edge { public: // i want have different constructor depending on // whether Vertex is (directly or indirectly) derived from Degree Edge(Enable_if<Is_Degree<Satellite>(), Vertex<Satellite> &>fromVertex, Vertex<Satellite> &toVertex) : from(fromVertex), to(toVertex){ ++to.inDeg; } Edge(Enable_if<!Is_Degree<Satellite>(), Vertex<Satellite> &>fromVertex, Vertex<Satellite> &toVertex) : from(fromVertex), to(toVertex){} private: Vertex<Satellite> &from; Vertex<Satellite> &to; }; 

The compiler complains about line 2:

" There is no type named ' type ' in ' std::__1::enable_if<false, Vertex<Degree> &> ': ' enable_if ' cannot be used to disable this declaration. "

There is no error if I remove the second Edge constructor. I want to know why and how to achieve my goal, as described in the commentary.

+5
source share
1 answer

This is due to the fact that the substitution occurs (and is not performed) outside the immediate context . Type template parameters involved in std::enable_if must come directly from the template that the compiler tries to create when the function / specialization is required for the existence of the context and are not known to this point. Otherwise, the compiler may reject your code.

A possible workaround is to turn the constructors into templates and by default use their parameters for the template parameter value of the enclosing class:

 template <typename S = Satellite> // ^-----v Edge(Enable_if<Is_Degree<S>(), Vertex<Satellite> &>fromVertex, Vertex<Satellite> &toVertex) : from(fromVertex), to(toVertex){ ++to.inDeg; } template <typename S = Satellite> // ^------v Edge(Enable_if<!Is_Degree<S>(), Vertex<Satellite> &>fromVertex, Vertex<Satellite> &toVertex) : from(fromVertex), to(toVertex){} 

Demo

+7
source

All Articles