我试图了解类型特征传播背后的机制,如http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0602r4.html 中std::optional 所述。复制操作的处理有细微的差别,复制操作应有条件地定义为删除,而移动操作则不应参与重载决议。
这种差异的原因是什么,我将如何测试后者?例子:
#include <type_traits>
#include <optional>
struct NonMoveable {
NonMoveable() = default;
NonMoveable(NonMoveable const&) = default;
NonMoveable(NonMoveable&&) = delete;
NonMoveable& operator=(NonMoveable const&) = default;
NonMoveable& operator=(NonMoveable&&) = delete;
};
// Inner traits as expected
static_assert(!std::is_move_constructible<NonMoveable>::value);
static_assert(!std::is_move_assignable<NonMoveable>::value);
// The wrapper is moveable, via copy operations participating in
// overload resolution. How to verify that the move operations don't?
static_assert(std::is_move_constructible<std::optional<NonMoveable>>::value);
static_assert(std::is_move_assignable<std::optional<NonMoveable>>::value);
int main(int argc, char* argv[])
{
NonMoveable a1;
NonMoveable a2{std::move(a1)}; // Bad, as expected
std::optional<NonMoveable> b1;
std::optional<NonMoveable> …Run Code Online (Sandbox Code Playgroud) 如果你有一个没有析构函数的类:
struct A {
~A() = delete;
};
Run Code Online (Sandbox Code Playgroud)
该标准不允许我"本地"分配该类的实例:
int main()
{
A a; //error
}
Run Code Online (Sandbox Code Playgroud)
但是,如果我在免费商店分配它似乎没关系:
int main()
{
a *p = new A();
}
Run Code Online (Sandbox Code Playgroud)
只要我不在该指针上调用delete:
int main()
{
a *p = new A();
delete p; //error
}
Run Code Online (Sandbox Code Playgroud)
所以我的问题是,如果我在免费商店分配它,为什么标准让我有一个没有析构函数的类?我猜有一些用例吗?但到底是什么?
当我用GCC编译时:
struct A
{
A();
A(const A &);
A(A &&) = delete;
};
void ugh(A);
A bar()
{
A a;
ugh(a);
return(a);
}
Run Code Online (Sandbox Code Playgroud)
我收到错误:
x.cpp: In function ‘A bar()’:
x.cpp:14:13: error: use of deleted function ‘A::A(A&&)’
return(a);
^
x.cpp:5:5: note: declared here
A(A &&) = delete;
^
Run Code Online (Sandbox Code Playgroud)
实际上,将return语句中的a视为rvalue(因为它即将被销毁)确实是有意义的.但是,标准是否要求rvalues是匿名的?
此外,即使在这种情况下允许使用移动构造函数,为什么还需要它?为什么编译器不能使用复制构造函数,因为移动构造函数不可用?
他之前的问题的答案,返回本地对象是否需要移动语义?,主要解决我的问题,但不要触及命名变量如何成为没有调用std :: move()的右值.
编辑:这两个链接解释了为什么gcc的行为是正确的,并阐明了为什么标准需要这种行为: 为什么C++ 11删除的函数参与重载解析? http://en.cppreference.com/w/cpp/language/return
以下代码S通过const &&.
然而它返回0,表明S不可移动构造!
main根据标准,2 个标记结构中每一个的正确行为是什么?
如果返回0是正确的行为,其背后的原理是什么?
(为什么它不应该反映类型实际上是否可以通过移动构造?)
#include <algorithm>
struct S
{
S( ) { }
S(S &) { } // = delete; doesn't make any difference
S(S const &) { } // = delete; doesn't make any difference
S(S const &&) { }
S(S &&) = delete;
};
int main()
{
S const s1;
S s2(std::move(s1)); // OK for >= C++11
S s3((S())); // OK for >= C++17, …Run Code Online (Sandbox Code Playgroud) 采取以下,
template<class T>
struct Foo {
Foo(){}
// a template constructor "generalized" over related types
template<class U>
Foo(Foo<U> const&) {
std::cout << 1;
}
// copy constructor
Foo(Foo const&) {
std::cout << 2;
}
};
Run Code Online (Sandbox Code Playgroud)
及其用户:
void main() {
Foo<int> f1;
Foo<const int> f2(f1); // prints 1
Foo<const int> f3(f2); // prints 2
}
Run Code Online (Sandbox Code Playgroud)
即使没有显式复制构造函数,编译器也会生成一个并使用它f3(f2).
有没有办法强制模板重载?例如,复制构造函数可以是SFINAE吗?这是为了避免代码重复,有趣的是,似乎没有办法使用委托构造函数(从复制构造函数委托给模板).
我正在尝试对我的函数中的所有局部变量使用auto.
请使用以下代码:
class obj
{
public:
obj() {};
obj( obj&& o ) = delete;
};
int main()
{
obj test0;
auto test1 = obj();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译代码:
$ g++ --std=c++1z main.cpp
main.cpp: In function ‘int main()’:
main.cpp:13:20: error: use of deleted function ‘obj::obj(obj&&)’
auto test1 = obj();
Run Code Online (Sandbox Code Playgroud)
请注意,定义test0完全没问题,但尝试执行完全相同类型的test1声明是编译器错误.显然应该是编译器错误,但在这种情况下,是否意味着obj无法用auto定义?我正在使用我无法控制的QT对象来解决这个问题.
我还在使用C++ 98格式来声明变量,还是有其他方法可以使用auto?
谢谢!!!