如何基于类模板参数禁用成员函数?

时间:2019-09-23 18:28:53

标签: c++ class templates sfinae

为说明这种情况,我们假设一个最小的示例:一个Vector模板类,其尺寸作为非类型模板参数。尺寸允许时,此类将提供x()y()(等)访问器:

template <int N_dimension>
class Vector
{
public:
    // ctors, etc.    
    int &x();

    template <class = std::enable_if_t<(N_dimension>2)>> int &y();

private:
    std::array<int, N_dimension> mData;
};

但是,这是行不通的,因为enable_if仅可以应用于推导的模板参数。

我们当前的解决方法看起来很麻烦:

    template <int N=N_dimension, class = std::enable_if_t<(N>2)>> int &y();

此外,它还需要在定义中进行静态声明以确保它是万无一失的(因为现在客户端代码可以将N的显式值赋予与实际尺寸不匹配的值。编辑:或 SergeyA 指出的匿名第二个模板参数的显式值。


是否有更直接的方法可以用C ++表示?

2 个答案:

答案 0 :(得分:4)

在这里我将不再使用SFINAE,只需将代码分成如下接口和私有实现即可:

int& y() {
    return y_impl(std::bool_constant<N > 2>{});
}

private:
int& y_impl(std::true_type ) {
    // impl
}
int& y_impl(std::false_type ) {
    static_assert(N > 2 /* always false */, "Wrong number of dimensions!");
}

此处的拆分是假设yN <= 2时不可编译,以减少错误消息的混乱情况。如果不是这种情况,则static_assert正文中的单个y就足够了。

答案 1 :(得分:3)

在C ++ 20中,您可以简单地使用requires来丢弃方法:

template <int N>
class Vector
{
public:
    int &x();
    int &y() requires(N >= 2);

private:
    std::array<int, N_dimension> mData;
};

在以前的版本中,它更为冗长:

template <std::size_t N>
class Vector
{
public:
    int &x();

    template <std::size_t M = N, std::enable_if_t<(M >= 2 && M == N), int> = 0>
    int &y();

private:
    std::array<int, N_dimension> mData;
};