为什么 is_copy_constructible return 在 MSVC12 中对 unique_ptr 为真

Why does is_copy_constructible return true for unique_ptr in MSVC12

我原以为这个静态断言会触发:

#include <type_traits>
#include <memory>

int main() {
  static_assert(std::is_copy_constructible<std::unique_ptr<int>>::value, "UPtr has copy constructor?");
}

但事实并非如此。

使用 MSVC12 编译:

Microsoft (R) C/C++ Optimizing Compiler Version 18.00.31101 for x64

static_assert 应该触发,std::unique_ptr has an implicitly deleted copy constructor, so this is a bug. This looks related to this bug report std::is_copy_constructible is broken:

(1) std::is_copy_constructible returns true for types with deleted copy constructors.

(2) std::is_copy_constructible returns true for types that compose types that are not copy constructible.

响应是:

Thanks for reporting this bug. We've fixed it, and the fix will be available in the next major version of Visual Studio after 2013.

另请参阅此错误报告:std::is_copy_constructible doesn't work correctly

请注意,断言在 webcompiler which is using an up to date version of Visual Studio. The last update was on Dec 3, 2015. The assert also fires on clang(see it live) 和 gcc.

上触发

我发现了一个错误报告:A strange behavior of std::is_copy_constructible,它与您的代码非常相似:

static_assert(std::is_copy_constructible<std::unique_ptr<int>>::value, "");

那里的回应是:

Thanks for reporting this bug. We've already fixed it, and the fix is available in VS 2015 Preview.

不清楚,Visual Studio 哪个版本修复了这个问题。一个回复说是 2013 年末版本,而后一个回复说是 2015 预览版。

这里有四种制作方法 class non-copyable:

#include <stdio.h>
#include <type_traits>

class A {
public:
    A(const A&) = delete;
    void operator=(const A&) = delete;
};

class B {
private:
    B(const B&) = delete;
    void operator=(const B&) = delete;
};

class C {
public:
    C(const C&) = delete;
    void operator=(const C&) = delete;
    void operator=(C) = delete;
};

class D {
private:
    D(const D&) = delete;
    void operator=(const D&) = delete;
    void operator=(D) = delete;
};

int main() {
    printf("%d %d\n", std::is_copy_constructible<A>::value, std::is_copy_assignable<A>::value);
    printf("%d %d\n", std::is_copy_constructible<B>::value, std::is_copy_assignable<B>::value);
    printf("%d %d\n", std::is_copy_constructible<C>::value, std::is_copy_assignable<C>::value);
    printf("%d %d\n", std::is_copy_constructible<D>::value, std::is_copy_assignable<D>::value);
}

在 MSVC2013 x64 (18.00.40629 for x64) 上,它打印:

1 1    //A
0 1    //B
1 0    //C
0 0    //D

在正确的编译器上,所有八个值都必须为零。

不幸的是,这 不是 提供解决 MSVC2013 中错误的好方法,即使对于您自己的 classes 也是如此。因为如果你声明赋值运算符按值接受参数,那么你不能在同一个class中声明移动赋值(任何移动赋值都不会编译,因为有歧义的重载)。

P.S. 固定分配的关键思想取自 this related answer.