为什么编译器说:'enable_if'不能用来禁用这个声明?

问题描述 投票:6回答:1
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;
};

编译器在第2行抱怨。

"没有名为''的类型。type'中的'。std::__1::enable_if<false, Vertex<Degree> &>': 'enable_if'不能用来禁用这个声明。"

如果我删除Edge的第二个构造函数,就不会出现错误。我想知道为什么,以及如何达到我在评论中描述的目的。

c++ c++11 templates sfinae enable-if
1个回答
8
投票

这是因为替换是在一个叫做 即时语境. 涉及的模板参数类型 std::enable_if 该来 径直 的模板,当上下文需要一个函数特殊化时,编译器会尝试将其实例化,而在这之前是未知的。否则,编译器可以随意拒绝你的代码。

一个可能的变通方法是将构造函数变成模板,并将其参数默认为封装类的模板参数值。

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

© www.soinside.com 2019 - 2024. All rights reserved.