为什么C++ 11使" deleted"函数参与重载决策?
为什么这有用?或者换句话说,为什么它们被隐藏而不是被完全删除?
Nic*_*las 112
= delete语法的一半目的是能够阻止人们使用某些参数调用某些函数.这主要是为了防止某些特定场景中的隐式转换.为了禁止特定的过载,它必须参与重载决策.
您引用的答案为您提供了一个完美的例子:
struct onlydouble {
onlydouble(std::intmax_t) = delete;
onlydouble(double);
};
Run Code Online (Sandbox Code Playgroud)
如果delete完全删除了该函数,那将使= delete语法等效于此:
struct onlydouble2 {
onlydouble2(double);
};
Run Code Online (Sandbox Code Playgroud)
你可以这样做:
onlydouble2 val(20);
Run Code Online (Sandbox Code Playgroud)
这是合法的C++.编译器将查看所有构造函数; 它们都没有直接采用整数类型.但其中一个人可以在隐式转换后接受它.所以它会称之为.
onlydouble val(20);
Run Code Online (Sandbox Code Playgroud)
这不是合法的C++.编译器将查看所有构造函数,包括deleted 构造函数.它将看到完全匹配,via std::intmax_t(将与任何整数文字完全匹配).因此编译器会选择它然后立即发出错误,因为它选择了一个deleted函数.
= delete意思是"我禁止这个",而不仅仅是"这不存在".这是一个更强烈的声明.
我问为什么C++标准说=删除意味着"我禁止这个"而不是"这不存在"
这是因为我们不需要特殊的语法来说"这不存在".我们通过简单地不声明所讨论的特定"这个"来隐含地得到这个."我禁止这个"代表了一种没有特殊语法就无法实现的结构.所以我们得到特殊的语法来说"我禁止这个"而不是另一个.
您将通过具有明确的获得唯一的功能"此不存在"语法是防止有人从后宣布其存在.而这仅仅是没有用到需要自己的语法.
否则无法声明复制构造函数不存在,并且它的存在可能导致无意义的歧义.
复制构造函数是一个特殊的成员函数.每个类总是有一个拷贝构造函数.正如他们总是有一个复制赋值运算符,移动构造函数等.
这些功能存在; 问题只是称呼它们是否合法.如果你试图说这= delete意味着它们不存在,那么规范就必须解释它对函数不存在意味着什么.这不是规范处理的概念.
如果您尝试调用尚未声明/定义的函数,则编译器将出错.但它会因为未定义的标识符而出错,而不是因为"函数不存在"错误(即使您的编译器以这种方式报告).各种构造函数都由重载决策调用,因此它们的"存在"在这方面得到了处理.
在每种情况下,都有一个通过标识符声明的函数,或者一个构造函数/析构函数(也通过标识符声明,只是一个类型标识符).运算符重载隐藏了语法糖的标识符,但它仍然存在.
C++规范无法处理"不存在的函数"的概念.它可以处理过载不匹配.它可以处理过载歧义.但它不知道什么不存在.所以= delete在的更为常用的术语定义为"试图把这种失败",而不是不太有用"假装我从来没有写过这条线."
再次,重新阅读第一部分.你不能用"功能不存在" 来做到这一点.这是为什么以这种方式定义的另一个原因:因为= delete语法的一个主要用例是能够强制用户使用某些参数类型,显式转换等等.基本上,要隐藏隐式类型转换.
你的建议不会这样做.
Ola*_*che 10
"C++工作草案2012-11-02"没有提供此规则背后的基本原理,仅举几个例子
8.4.3删除的定义[dcl.fct.def.delete]
...
3 [ 示例:可以强制执行非默认初始化和非整数初始化
struct onlydouble {
onlydouble() = delete; // OK, but redundant
onlydouble(std::intmax_t) = delete;
onlydouble(double);
};
Run Code Online (Sandbox Code Playgroud)
- 结束示例 ]
[ 示例:通过使用该类的用户声明的运算符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[]
Run Code Online (Sandbox Code Playgroud)
- 结束示例 ]
[ 示例:通过使用复制构造函数和复制赋值运算符的已删除定义,然后提供移动构造函数和移动赋值运算符的默认定义,可以使类不可复制,即仅移动.
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
Run Code Online (Sandbox Code Playgroud)
- 结束例子 ]