以下代码编译正常:
g++ -std=c++11 test.cpp -Wall -Wextra -Wfatal-errors && ./a.out
Run Code Online (Sandbox Code Playgroud)
但是,如果我从中移除花括号{*this}并使用*this,我将面临错误:
错误:使用已删除的函数'Obj :: Position :: Position(Obj :: Position &&)'
{*this}和之间有什么区别*this?
class Obj
{
template<bool> friend class Position;
double data;
public:
class Position
{
const Obj& ref;
public:
inline Position(const Obj& ref): ref(ref){}
inline Position(Position const &) = delete;
inline Position(Position &&) = delete;
};
inline Obj(){}
inline Obj(const double &data): data(data){}
inline auto get_pos() const-> Position{return {*this};} /* <--- here */
inline auto get_pos()-> Position{return {*this};}
};
int main()
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
Pra*_*ian 37
当花括号出现时,你是copy-list-initialize返回值,不涉及复制/移动构造函数.该返回值被就地建造使用的Position(const Obj&)构造函数.
请注意,如果您创建Position(const Obj&)构造函数,即使使用大括号也无法编译代码,explicit因为copy-list-initialization不允许调用显式构造函数.
如果省略花括号,则在语义上Position在函数内构造临时对象,并从该临时值构造返回值.实际上,大多数实现都会忽略移动构造,但它仍然需要一个可行的移动构造函数才能存在,而这种情况并非如此,因为它已被明确删除.这就是你的代码在没有大括号的情况下无法编译的原因.
使用C++ 17编译器,即使没有大括号,您的代码也会编译,因为保证了copy-elision.
Tob*_*ias 17
两者之间的区别非常微妙.C++ 11引入了功能列表初始化(有时也称为大括号初始化):
在C++ 11之前,当你想要默认构造和o类型的对象Obj并构造一个Position pfrom时o,你必须写
Obj o; // default construct o
Obj::Position p(o); // construct p using Position(Obj const&)
Run Code Online (Sandbox Code Playgroud)
初学者的一个常见错误(特别是Java背景)是尝试写这个:
Obj o(); // mistake: declares a function o returning an Obj
Obj::Position p(o); // error: no constructor takes a function
Run Code Online (Sandbox Code Playgroud)
第一行声明一个函数,第二行尝试Position使用一个以函数指针作为参数的构造函数创建一个函数.为了获得统一的初始化语法,C++ 11引入了列表初始化:
Obj oo{}; // new in C++11: default construct o of type Obj
Obj::Position p1(oo); // possible before (and after) C++11
Obj::Position p2{oo}; // new in C++11: construct p2 using Position(Obj const&)
Run Code Online (Sandbox Code Playgroud)
这种新的语法也适用于return-statements,这导致你的问题的回答:之间差异return {*this};以及return *this;在于,前者初始化返回值直接从*this,而后者首先将*this一个临时Position对象,然后间接地初始化返回值来自这个临时的,因为复制和移动构造函数都已被明确删除而失败.
正如之前的海报所指出的那样,大多数编译器都忽略了这些临时对象,因为它们对任何事物都没有用处; 但这只有在理论上可以使用时才有可能,因为副本或移动构造函数都可用.因为这导致了很多困惑(为什么我需要在我的return语句括号?时,编译器会在的Elid复制或没有?),C++ 17废除了这些不必要的临时对象,并初始化返回值直接在两种情况(return {*this};和return *this).
您可以使用支持C++ 17的编译器来尝试此操作.在clang 4.0或gcc 7.1中,您可以传递--std=c++1z,并且您的代码应该使用和不使用大括号进行编译.
isp*_*zax 13
这个不错!这是因为return {...}意味着"返回使用列表初始值设定项初始化的函数返回类型的对象...".
列表初始值设定项在此处有更详细的描述:
http://en.cppreference.com/w/cpp/language/list%20initialization
所以,区别在于{*this}调用:
inline Position(const Obj& ref): ref(ref){}
Run Code Online (Sandbox Code Playgroud)
而*this试图转换Obj&到Position使用显式删除赋值运算符(预C++ 11,他们将不得不作出private的,你会得到一个更令人困惑的错误消息,如果列表中的初始化将可...):
inline Position(Position const &) = delete;
inline Position(Position &&) = delete;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3174 次 |
| 最近记录: |