why compiler said: 'enable_if' cannot be used to disable this declaration

*爱你&永不变心* 提交于 2019-12-08 21:23:09

问题


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 at line 2:

"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 constructor of Edge. I want know why, and how to attain my purpose as described in the comment.


回答1:


This is because substitution takes place (and fails) outside of an immediate context. Type template parameters involved in std::enable_if should come directly from a template that a compiler attempts to instantiate when a function/specialization is required to exist by a context, and that are unknown prior to that point. Otherwise, the compiler is free to reject your code.

A possible workaround is to turn the constructors into templates and default their parameters to the value of the template parameter 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



来源:https://stackoverflow.com/questions/32503687/why-compiler-said-enable-if-cannot-be-used-to-disable-this-declaration

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!