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.
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){}