【问题标题】:What is the point of using delete on a non-member function?在非成员函数上使用 delete 有什么意义?
【发布时间】:2017-02-19 20:56:03
【问题描述】:

摘自标准 20.12 [function.objects]:

template <class T> reference_wrapper<T> ref(T&) noexcept;
template <class T> reference_wrapper<const T> cref(const T&) noexcept;
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;

我习惯于在成员函数的上下文中看到=delete。目的是禁止编译器提供的操作。例如,使类不可复制或不可移动。

然而,在这种情况下,意图似乎是意图的文档。这是正确的吗?在其他情况下,在非成员函数上使用=delete 是可取、可取或不可避免的吗?

【问题讨论】:

  • 您可以在您认为函数需要太多参数集的所有情况下使用它。因此,您采用邪恶的参数并创建一个仅与这些参数匹配但更好的已删除函数。例如,您可能希望阻止f(int*) 接受0(只接受nullptr 用于空指针)。所以你可以添加一个f(int) = delete; 重载。

标签: c++ c++11


【解决方案1】:

我知道明确delete 释放函数的一般原因有两个:拒绝不需要的隐式转换,以及为用户提供更好的错误体验。


拒绝不需要的隐式转换

const 的一个有用特性是临时对象可以绑定到对const 的引用。所以这行得通:

void foo(const int& );
foo(42); // ok

临时的42 绑定到函数的引用参数,并且它的生命周期与该引用参数绑定。

现在,考虑std::cref()。我们的目标是通过这个reference_wrapper 到某个地方,所以我们需要底层引用来保持活力。如果我们只是有这个重载:

template <class T>
reference_wrapper<const T> cref(const T&) noexcept;

然后我可以写std::cref(42)。这会很好,我会得到一个std::reference_wrapper&lt;const int&gt; - 除非它是一个悬空的参考。该代码不可能工作。

为了修复这个明显的错误,我们也有这个重载:

template <class T> void cref(const T&&) = delete;

也就是说,我们正在显式删除(或定义为已删除)采用任何右值的重载。现在,在进行重载解析时,当我传入一个右值时,第二次重载是首选,并且该重载格式不正确,编译器会通知我们我们的错误(愚蠢的我,我不能这样做cref(42)!)我不得不花几个小时在 gdb 上试图弄清楚为什么我没有对象。

标准库中的其他示例有:

为用户提供更好的诊断

另一类示例可能是为受约束的函数提供更好的诊断。假设我有一个只对整数类型有意义的函数:

template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
void foo(T);

我尝试用非整数类型调用它:

foo(4.2); // error: no matching function

根据需要,这会失败。但是你得到的错误并不是很有意义。特别是如果有其他重载。有了概念画板,这会更好——希望,但不一定。

但是如果我添加相反的显式删除重载:

template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
void foo(T);

template <typename T, std::enable_if_t<!std::is_integral_v<T>, int> = 0>
void foo(T) = delete;

foo(4.2); // error: use of deleted function

这更加明确和直接。特别是如果foo 的作者提供了说明为什么这很重要的评论。基本上,这仍然是 SFINAE 友好的,同时还提供了 static_assert 直接指示失败的好处(而如果我们只是 static_asserted,我们会得到更清晰的信息,但我们会失去 SFINAE 友好性)。

确实,N4186 的动机是让该注释成为代码本身的一部分(尽管该提议被拒绝了)。那篇论文中的例子是:

template <typename T>
enable_if_t<has_compatible_vector_size<simd_float, T>::value, simd_float>
operator+(simd_float, T);

template <typename T>
enable_if_t<!has_compatible_vector_size<simd_float, T>::value, simd_float>
operator+(simd_float, T) = delete;

标准库中的一个例子是std::make_unique() 代表make_unique&lt;U[N]&gt;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-14
    • 1970-01-01
    相关资源
    最近更新 更多