【问题标题】:How to disable a member function based on a class template parameter?如何根据类模板参数禁用成员函数?
【发布时间】:2019-09-23 18:28:53
【问题描述】:

为了说明这种情况,让我们假设一个最小的例子: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++ 中表达这一点?

【问题讨论】:

  • 专业化是唯一的其他选择。但是“繁琐”的选项真的没有那么多;而且我不会担心有人指定显式模板参数。这就是 cmets 和文档的用途。发表评论说:不要指定任何参数,不要管它们。
  • 您还有另一个缺陷 - 通过将显式类型作为第二个模板参数客户端也可以实例化该函数。由于您似乎没有专门启用其他y(),以防N_dimension 大于2,您为什么需要它?只需留下static_assert,这比模板替换错误的行和行更具描述性。

标签: c++ class templates sfinae


【解决方案1】:

我会在这里取消 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 &lt;= 2时不可编译,以减少错误信息的混乱。如果不是这种情况,y 正文中的单个 static_assert 就足够了。

【讨论】:

  • 这种方法的一个限制是成员函数实际上并没有被删除,因此(据我所知)不可能使用is_detected等机制来测试它的缺失
【解决方案2】:

在 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;
};

【讨论】:

  • 哦,确实是错字。已删除。
猜你喜欢
  • 1970-01-01
  • 2011-04-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-23
  • 2017-09-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多