c++ - 当有用户定义的移动赋值运算符时,模板化的移动赋值运算符被删除
问题描述
我有一个带有复制构造函数的类,该构造函数仅在满足条件时才启用,例如在此示例中,当类型参数不是引用时。和一个既不能移动也不能复制的成员(比如互斥锁)。例如(https://wandbox.org/permlink/hRx51Ht1klYjN7v5)
#include <iostream>
#include <tuple>
#include <mutex>
using std::cout;
using std::endl;
template <typename T>
class Something {
public:
Something() {}
template <typename Type = T,
std::enable_if_t<!std::is_reference<Type>{}>* = nullptr>
Something(const Something&) {}
Something& operator=(Something&&) {
return *this;
}
std::mutex mutex_;
};
int main() {
auto&& one = Something<int>{};
auto two = one;
std::ignore = two;
}
当我编译这段代码时,我收到一条错误消息
copy constructor is implicitly deleted because 'Something<int>' has a user-declared move assignment operator
Something& operator=(Something&&) {
^
1 error generated.
好的,所以我尝试将相同的约束应用于移动赋值运算符
template <typename T>
class Something {
public:
Something() {}
template <typename Type = T,
std::enable_if_t<!std::is_reference<Type>{}>* = nullptr>
Something(const Something&) {}
template <typename Type = T,
std::enable_if_t<!std::is_reference<Type>{}>* = nullptr>
Something& operator=(Something&&) {
return *this;
}
std::mutex mutex_;
};
错误更改为此
copy constructor of 'Something<int>' is implicitly deleted because field 'mutex_' has an inaccessible copy constructor
std::mutex mutex_;
^
1 error generated.
关于如何解决这个问题的任何想法?当我明确想要默认构造不可移动不可复制成员时,为什么编译器会抱怨?当我删除约束时,这编译得很好https://wandbox.org/permlink/daqWAbF40MyfDJcN
解决方案
特殊成员函数(复制/移动)由它们的签名标识。当您尝试对它们进行模板化时,您正在定义具有另一个签名的模板,因为模板参数是模板签名的一部分,并且该功能与您尝试禁止的复制/移动 c'tors 无关。
为了完整起见,引用标准,强调我的:
类 X的非模板构造函数是复制构造函数,如果它的第一个参数是 X&、const X&、volatile X& 或 const volatile X&,并且没有其他参数,或者所有其他参数都有默认参数([dcl. fct.default])。
在描述其他特殊成员时也会出现类似的措辞。它们必须是非模板。
因此,您不会使用 SFINAE 影响这些功能。而且您不能直接使用 SFINAE 影响它们,因为编译器会确保它们始终存在。影响它们的生成或缺失的唯一方法是从基类继承(有条件地,甚至),或者拥有成员数据,这将导致它们被定义为删除。
假设两年内没有任何变化,一线希望是,在 C++20 中,可以使用requires
子句约束复制构造函数(或任何特殊成员):
Something(const Something&) requires !std::is_reference_v<T> {}
推荐阅读
- javascript - Bootstrap-multiselect 显示隐藏 div 元素
- powershell - 问题转移 ListboxItem 并在 Hashtable 中解决
- javascript - 添加两个数字并显示结果而无需单击按钮
- postgresql - 在 Google Cloud Postgres 上启用逻辑复制
- scala - 如何在注释宏中操作修饰符
- angular - 发送带有角度和离子框架的附加可观察对象的get
- javascript - TINYMCE 编辑器外部模板:未捕获的类型错误:无法读取未定义的属性“indexOf”
- python-3.7 - 如何使用 python 3.7 在 csv 文件中读写?
- tcp - netcat 和 scp 在身份验证、保密性和性能方面谁更好?如何
- postgresql - 为什么我的 import.sql 文件没有自动运行?