c++ - 如何获得类型是否真正可移动构造
问题描述
以这段代码为例:
#include <type_traits>
#include <iostream>
struct Foo
{
Foo() = default;
Foo(Foo&&) = delete;
Foo(const Foo&) noexcept
{
std::cout << "copy!" << std::endl;
};
};
struct Bar : Foo {};
static_assert(!std::is_move_constructible_v<Foo>, "Foo shouldn't be move constructible");
// This would error if uncommented
//static_assert(!std::is_move_constructible_v<Bar>, "Bar shouldn't be move constructible");
int main()
{
Bar bar {};
Bar barTwo { std::move(bar) };
// prints "copy!"
}
因为 Bar 是从 Foo 派生的,所以它没有移动构造函数。它仍然可以通过使用复制构造函数来构造。我从另一个答案中了解了为什么它选择复制构造函数:
if
y
is of typeS
, thenstd::move(y)
, of typeS&&
, is reference compatible with typeS&
。因此S x(std::move(y))
完全有效并调用复制构造函数S::S(const S&)
。——Lærne,理解
std::is_move_constructible
所以我明白为什么右值从移动到左值复制“降级”,因此为什么std::is_move_constructible
返回真。但是,有没有办法检测一个类型是否真正可移动构造,不包括复制构造函数?
解决方案
有人声称无法检测到移动构造函数的存在,并且在表面上它们似乎是正确的——&&
绑定到的方式const&
使得无法判断哪些构造函数存在于类的接口中。
然后我想到了——C++ 中的移动语义不是单独的语义……它是复制语义的“别名”,是类实现者可以“拦截”并提供替代实现的另一个“接口”。所以问题是“我们可以检测到移动 ctor 的存在吗?” 可以重新表述为“我们可以检测到两个复制接口的存在吗?”。事实证明,我们可以通过(ab)使用重载来实现这一点——当有两种同样可行的方法来构造一个对象并且可以使用 SFINAE 检测到这一事实时,它无法编译。
30 行代码值一千字:
#include <type_traits>
#include <utility>
#include <cstdio>
using namespace std;
struct S
{
~S();
//S(S const&){}
//S(S const&) = delete;
//S(S&&) {}
//S(S&&) = delete;
};
template<class P>
struct M
{
operator P const&();
operator P&&();
};
constexpr bool has_cctor = is_copy_constructible_v<S>;
constexpr bool has_mctor = is_move_constructible_v<S> && !is_constructible_v<S, M<S>>;
int main()
{
printf("has_cctor = %d\n", has_cctor);
printf("has_mctor = %d\n", has_mctor);
}
笔记:
您可能应该能够将此逻辑与其他
const/volatile
重载混淆,因此此处可能需要一些额外的工作怀疑这种魔法是否适用于私有/受保护的构造函数——另一个值得关注的领域
似乎在 MSVC 上不起作用(就像传统一样)
推荐阅读
- azure-data-factory - 使用数据流以分层格式存储文件时出现 Azure 数据工厂错误
- python-3.x - Tensorflow 2.2.0 无法加载动态库“libcudnn.so.7”
- sql-server - SSIS 加载带有动态列的 Excel 文件
- javascript - Vue:全局 v 指令在一个组件中工作,但不在另一个组件中
- informatica - Informatica 中的更新大约需要很长时间。(38 小时)
- numpy - 解决apt_pkg和Numpy安装问题
- session - NextJS 和 NextAuth 会话用户对象由于 [...nextauth.ts] 被触发重新编译而丢失
- java - TargetDataline 返回 -1(Audiosystem.NOT_SPECIFIED)
- python - 将无人机 (UAV) 入侵检测数据集下载并导入 Jupiter Notebook
- node.js - Express 多路由匹配引发错误 [ERR_HTTP_HEADERS_SENT]:在将标头发送到客户端后无法设置标头