为什么C++11删除的函数会参与过载解决

Why do C++11-deleted functions participate in overload resolution?

本文关键字:解决 C++11 删除 函数 为什么      更新时间:2023-10-16

为什么C++11让"deleted"函数参与过载解析
为什么这有用?或者换句话说,为什么它们被隐藏而不是被完全删除?

= delete语法的一半目的是防止人们使用某些参数调用某些函数。这主要是为了防止某些特定场景中的隐式转换。为了禁止特定的过载,它必须参与过载解决。

你引用的答案给了你一个完美的例子:

struct onlydouble {
  onlydouble(std::intmax_t) = delete;
  onlydouble(double);
};

如果delete完全删除了该函数,则= delete语法等效于以下内容:

struct onlydouble2 {
  onlydouble2(double);
};

你可以这样做:

onlydouble2 val(20);

这是合法的C++。编译器将查看所有构造函数;它们都没有直接采用整数类型。但他们中的一个可以在隐式转换后接受它。所以它会这么说。

onlydouble val(20);

这是而不是合法的C++。编译器将查看所有构造函数,包括delete d构造函数。它将通过std::intmax_t(它将与任何整数文本完全匹配(看到完全匹配。因此编译器会选择它,然后立即发出错误,因为它选择了deleted函数。

= delete的意思是"我禁止这样做",而不仅仅是"这不存在"。这是一个更强有力的说法。

我在问为什么C++标准说=删除意味着"我禁止这个"而不是"这个不存在">

这是因为我们不需要特殊的语法来说"这不存在"。我们通过简单地不声明特定的"这个"来隐含地得到这一点。"我禁止这样做"代表了一种结构,如果没有特殊语法,就无法实现。所以我们有特殊的语法来说"我禁止这个",而不是其他事情。

通过明确的"这不存在"语法,你唯一能获得的功能是防止有人后来宣布它存在。这还不够有用,不需要它自己的语法。

否则就无法声明复制构造函数不存在,并且它的存在可能会导致无意义的歧义。

复制构造函数是一个特殊的成员函数。每个类总是都有一个复制构造函数。正如他们总是有一个复制赋值运算符,移动构造函数等

这些功能是存在的;问题只是打电话给他们是否合法。如果你试图说= delete意味着它们不存在,那么规范就必须解释函数不存在意味着什么。这不是规范处理的概念。

如果您试图调用尚未声明/定义的函数,那么编译器将出错。但它会因为未定义的标识符而出错,而不是因为"函数不存在"错误(即使编译器以这种方式报告它(。各种构造函数都是通过重载解析来调用的,所以它们的"存在"是在这方面处理的。

在每种情况下,都有一个通过标识符声明的函数,或者一个构造函数/析构函数(也通过标识符声明,只是一个类型标识符(。运算符重载将标识符隐藏在语法糖后面,但它仍然存在。

C++规范无法处理"不存在的函数"的概念。它可以处理重载不匹配。它可以处理超负荷的模糊性。但它不知道什么是不存在的。因此,= delete的定义是更有用的"尝试称之为失败",而不是不太有用的"假装我从未写过这行">

再次重读第一部分。不能用"函数不存在"来实现这一点。这也是它被这样定义的另一个原因:因为= delete语法的主要用例之一是能够强制用户使用某些参数类型、显式强制转换等等。基本上,是为了避免隐式类型转换。

你的建议不会那样做。

2012-11-02 C++工作草案没有提供该规则背后的基本原理,只是的一些例子

8.4.3已删除定义[dcl.fct.def.delete]

3[示例:可以使用强制执行非默认初始化和非积分初始化

struct onlydouble {  
  onlydouble() = delete; // OK, but redundant  
  onlydouble(std::intmax_t) = delete;  
  onlydouble(double);  
};  

--结束示例]
示例:通过使用已删除的类的定义,可以防止在某些新表达式中使用类用户为该类声明了new运算符。

struct sometype {  
  void *operator new(std::size_t) = delete;  
  void *operator new[](std::size_t) = delete;  
};  
sometype *p = new sometype; // error, deleted class operator new  
sometype *q = new sometype[3]; // error, deleted class operator new[]  

--结束示例]
示例:通过使用已删除的副本定义,可以使类不可复制,即仅移动构造函数和复制赋值运算符,然后提供move构造函数的默认定义和移动分配运算符。

struct moveonly {  
  moveonly() = default;  
  moveonly(const moveonly&) = delete;  
  moveonly(moveonly&&) = default;  
  moveonly& operator=(const moveonly&) = delete;  
  moveonly& operator=(moveonly&&) = default;  
  ~moveonly() = default;  
};  
moveonly *p;  
moveonly q(*p); // error, deleted copy constructor  

--结束示例]