【发布时间】:2019-01-24 21:02:57
【问题描述】:
以这段代码为例:
#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 派生的,所以它没有移动构造函数。它仍然可以通过使用复制构造函数来构造。我从另一个答案中了解到为什么它选择复制构造函数:
如果
y的类型为S,则std::move(y)的类型为S&&,与S&类型的引用兼容。因此S x(std::move(y))完全有效并调用复制构造函数S::S(const S&)。
所以我明白为什么右值从移动到左值复制“降级”,因此为什么std::is_move_constructible 返回真。但是,有没有办法检测一个类型是否真正可移动构造,不包括复制构造函数?
【问题讨论】:
-
我建议寻找一种方法来检查给定类型是否具有具有特定签名的成员函数——很确定有一种方法可以做到这一点(需要一些元编程魔法)。喜欢this。您也许可以将其用于构造函数...
-
这是一个 XY 问题。为什么需要知道是否有定义的移动构造函数?您打算如何使用这些信息?
-
您可以通过简单地不编写可复制但不可移动的类来轻松避免此问题。
-
@PasserBy 我在这里说得更笼统。我不知道OP。但一般来说,移动对象可能“快得可以接受”,而复制则不然。 (即,如果对象拥有千兆字节的数据)在这种情况下,当它无法移动而不是无意允许大副本时,编译时错误将很有用。
-
即使有移动构造函数也不意味着它不复制!也就是说,编译器肯定会相信这个类是“真正可移动构造的:
struct baz: foo { baz(baz const&) = default; baz(&& other): baz(other) {} };顺便说一句,这种行为与您的bar相同,但您似乎希望对这个问题有不同的答案。
标签: c++ stl move-semantics typetraits