我本以为这个静态断言会触发:
#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++优化编译器版本18.00.31101适用于x64
我本以为这个静态断言会触发:
#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++优化编译器版本18.00.31101适用于x64
static_assert
应该会触发,因为 std::unique_ptr 有一个隐式删除的复制构造函数,因此这是一个 bug。这似乎与这个 bug 报告 std::is_copy_constructible is broken 有关:
回复如下:(1) std::is_copy_constructible 返回 true,对于带有已删除复制构造函数的类型。
(2) std::is_copy_constructible 返回 true,对于组成不可复制类型的类型。
还请查看此 bug 报告:std::is_copy_constructible doesn't work correctly。感谢您报告此错误。我们已经修复了它,并且修复将在 2013 年后的 Visual Studio 的下一个主要版本中提供。
Dec 3, 2015
。assert 还会在 clang(see it live) 和 gcc 上触发。static_assert(std::is_copy_constructible<std::unique_ptr<int>>::value, "");
回复如下:
感谢您报告此错误。我们已经修复了它,并且在VS 2015 Preview中提供了修复程序。
不清楚这个问题是在哪个版本的Visual Studio中修复的。有一个回复说是2013年后期版本,而后面的回复则说是2015年预览版。
以下是四种使类不可复制的方法:
#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);
}
18.00.40629 for x64
) 上,它会打印出:1 1 //A
0 1 //B
1 0 //C
0 0 //D
在一个合适的编译器上,所有八个值都必须是零。
不幸的是,这并不能为解决MSVC2013中的错误提供一个好的方法,即使对于你自己的类也是如此。因为如果你声明接受值参数的赋值运算符,那么你不能在同一类中声明移动赋值运算符(任何移动赋值都无法编译,因为存在歧义重载)。
P.S. 修复赋值的关键思想来自于this related answer。