std::p ackaged_task 应该删除带有 const 参数的复制 c'tor
std::packaged_task should have deleted copy c'tor with const parameter
Link https://cplusplus.github.io/LWG/issue2067 提供了以下讨论:
类模板packaged_task是仅移动类型,具有以下形式的已删除复制操作:
packaged_task(packaged_task&) = delete;
packaged_task& operator=(packaged_task&) = delete;
请注意,参数类型是非常量。这对我来说不像是一个错字,这种形式似乎从 N2276 的第一篇提案论文中就存在。在引入默认的特殊成员函数之前,使用复制构造函数的任何一种形式都没有太大区别,但现在它产生了可观察到的差异。德国C++新闻组上的一个问题引起了我的注意,其中提出了为什么以下代码无法在最近的 gcc 上编译的问题:#include <utility> #include <future> #include <iostream> #include <thread> int main() { std::packaged_task<void()> someTask([]{ std::cout << std::this_thread::get_id() << std::endl; }); std::thread someThread(std::move(someTask)); // Error here // Remainder omitted }
事实证明,该错误是由某些返回类型的 std::bind 的实例化产生的,该返回类型使用了默认的复制构造函数,这会导致与 [class.copy] p8 的 const 声明冲突。
这个问题的某些方面可能与核心语言有关,但我认为它不仅仅是对程序员的服务,如果库将复制操作的通常形式(即那些具有 const 第一个参数类型的操作(声明为删除packaged_task以防止此类问题。
谁能解释一下标记语句的含义?我不知道缺少的 const qualifer 如何影响编译过程,以及如何在标准中解释这种行为。 将 const 添加到已删除的复制构造函数的参数中有什么意义?
下面是一个玩具示例:
struct problem {
problem()=default;
problem(problem&&)=default;
problem(problem&)=delete;
};
template<class T>
struct bob {
T t;
bob()=default;
bob(bob&&)=default;
bob(bob const&)=default;
};
int main() {
problem p;
problem p2 = std::move(p);
bob<problem> b;
bob<problem> b2 = std::move(b);
}
bob<problem>
无法编译,因为bob(bob const&)=default
在与problem(problem&)=delete
交互时出错。
可以说,当标准确定它无法实现bob(bob const&)
时,它"应该"干净地出错,并将=default
视为=delete
(就像我们有problem(problem const&)=delete
一样(,但标准措辞在这种极端情况下不会完美无缺。 角落案例的这个角落会很奇怪和古怪,以至于我不确定将其=default
转换为=delete
的一般规则是正确的!
如果我们problem(problem const&)=delete
(好吧,packaged_task
(的修复将比我们为=default
ctor规则所做的任何事情都要干净得多。
现在标准钻研:
首先,很明显,上面bob<problem>
的隐式声明的复制构造函数将在[class.ctor]中具有签名bob(bob&)
。 我什至不会为此引用标准,因为懒惰。
我们去并显式默认bob(bob const&)
copy ctor,它在签名上与隐式声明的签名不同。
有关于显式默认函数的规则,它们与签名的冲突在 11.4.2 中。
在显式默认函数 [dcl.fct.def.default] 11.4.2/2 中
2 允许显式默认函数的类型
T1
F
与隐式声明时的类型不同T2
如下所示:—(2.1(
T1
和T2
可能有不同的 ref 限定符;和—(2.2(如果
T2
有一个类型为const C&
的参数,则对应的参数T1
可以是C&
类型。如果
T1
在任何其他方面与T2
不同,则:—(2.3(如果
F
是赋值运算符,并且返回类型T1
与返回类型不同T2
或者T1
的参数类型不是引用,则程序格式不正确;—(2.4( 否则,如果
F
在其第一个声明中明确默认,则将其定义为已删除;—(2.5( 否则,程序格式不正确。
默认的T1
,其中包含const&
不&
,因此(2.2(不适用。
我的阅读实际上已经抓住了它(2.4(;bob(bob const&)
的类型以不允许的方式与隐含声明的bob(bob&)
不同;但是第一次声明是default
的,所以它应该被delete
d。
我正在查看 n4713 草案版本;也许旧版本没有该条款。
- 当从函数参数中的临时值调用复制构造函数时
- 如果有一个模板构造函数只有一个泛型参数,为什么我必须有一个复制构造函数
- 为什么默认复制函数在按值发送参数时不调用?
- std::p ackaged_task 应该删除带有 const 参数的复制 c'tor
- 将参数传递给泛型 lambda 时复制构造函数不正确
- 如何确定捕获不可复制参数的 lambda 的类型?
- 复制 avcodec 参数
- 从函数参数 [C++] 复制整数数组
- 候选构造函数(隐式复制构造函数)不可行:第一个参数需要 l 值
- 将参数的省略复制为返回值
- 可变参数宏:无法通过"..."传递非平凡可复制类型的对象
- 复制构造函数参数为0
- 函数指针,可以采用具有常量引用或复制参数的函数
- 标准::函数复制参数
- 使用 std::string 参数和不可移动/可复制参数构建 std::map
- 在矢量中插入元素时,请避免复制参数
- 无意中复制参数
- std::bind 和 std::thread 总是复制参数背后的基本原理是什么?
- std::带可移动、不可复制参数的线程
- boost::bind()是否通过引用或值复制参数