Joh*_*erg 13 c++ aggregate rvo c++17
使用C++ 17,我们将有可能返回不可移动(包括不可复制)类型,例如std::mutex
,通过可以被认为是有保证的返回值优化(RVO):通过简化的值类别保证复制省略:
struct nocopy { nocopy(nocopy&) = delete; nocopy() = default; };
auto getRVO(){
return nocopy();
}
Run Code Online (Sandbox Code Playgroud)
我们还将具有结构化绑定,允许:
tuple<T1,T2,T3> f();
auto [x,y,z] = f();
Run Code Online (Sandbox Code Playgroud)
template<typename T1,typename T2,typename T3>
struct many {
T1 a;
T2 b;
T3 c;
};
// (Original questions missed 'many' on the next line. Thanks, T.C.)
auto f(){ return many{string(),5.7, false} };
auto [x,y,z] = f();
Run Code Online (Sandbox Code Playgroud)
但这些功能是否可以实现这样的功能呢?
auto get_ensured_rvo_str(){
return std::pair(std::string(),nocopy());
}
auto get_class_and_mutex(){
return many{SomeClass(),std::mutex(),std::string()};
}
int main(){
auto rvoStr = get_ensured_rvo_str().first;
auto [ mtx,sc,str ] = get_class_and_mutex();
}
Run Code Online (Sandbox Code Playgroud)
我的想法是,为了这个工作,它会在需要保证形成的集合体构造函数的参数RVO std::tuple
或many
,但不会是被命名为RVO(NRVO),这是特别不包括在P0144R2建议?
附注:P0144R2特别提到支持仅移动类型:
2.6仅移动类型
仅支持仅移动类型.例如:
Run Code Online (Sandbox Code Playgroud)struct S { int i; unique_ptr<widget> w; }; S f() { return {0, make_unique<widget>()}; } auto [ my_i, my_w ] = f();
T.C*_*.C. 10
Run Code Online (Sandbox Code Playgroud)template<typename T1,typename T2,typename T3> struct many { T1 a; T2 b; T3 c; }; auto f(){ return {string(),5.7, false} };
这不会编译.首先你永远不会说f
是回归many
.其次,类模板参数推导与构造函数一起工作,唯一的构造函数many
是隐式声明的默认,复制和移动构造函数.
你需要一个指南:
template<class T1, class T2, class T3>
many(T1, T2, T3) -> many<T1, T2, T3>;
Run Code Online (Sandbox Code Playgroud)
Run Code Online (Sandbox Code Playgroud)auto get_ensured_rvo_str(){ return std::pair(std::string(),nocopy()); }
这也不起作用.nocopy()
被物化为一个临时的,它绑定到pair
构造函数的引用参数,然后它尝试从它移动并失败.不允许或允许任何暂时的省略.
(当然,正如Nicol Bolas在他的回答中指出的那样,类成员访问get_ensured_rvo_str().first
实现了pair
返回值get_ensured_rvo_str
,所以rvoStr
实际上将从该first
物化临时的成员构造移动.但是在这之前你有一个问题.)
Run Code Online (Sandbox Code Playgroud)auto get_class_and_mutex(){ return many{SomeClass(),std::mutex(),std::string()}; } auto [ mtx,sc,str ] = get_class_and_mutex();
这很好(假设您有扣除指南).聚合初始化不会调用任何构造函数many
; 它使用相应的prvalue初始化程序直接初始化成员.
结构化绑定被定义为在提取对单个值的引用或伪引用的基础上工作.也就是说,如果你这样做:
auto [x,y,z] = f();
Run Code Online (Sandbox Code Playgroud)
你得到的是这样的事情:
auto HIDDEN_VALUE = f();
auto &x = get<0>(HIDDEN_VALUE);
auto &y = get<1>(HIDDEN_VALUE);
auto &z = get<2>(HIDDEN_VALUE);
Run Code Online (Sandbox Code Playgroud)
处理结构时x
,y
和,z
不会被引用; 它们将是"引用"实际数组成员的东西,但它不是实际的引用.重点是x
,y
并且z
永远不会复制任何东西.
因此,问题是是否HIDDEN_VALUE
被复制.很明显,HIDDEN_VALUE
价值构建.因此,如果返回f()
是prvalue,那么保证省略的规则将适用.
Run Code Online (Sandbox Code Playgroud)auto rvoStr = get_ensured_rvo_str().first;
表达式get_ensured_rvo_str()
是prvalue.但是,适用.first
它的结果不是 prvalue.施加.first
强制prvalue(在保证的省略规则下)构造一个临时的,并.first
应用于它.提取的元素(xvalue)将用于复制初始化rvoStr
.
所以在没有版本的标准下,副本被rvoStr
省略了.
Run Code Online (Sandbox Code Playgroud)return many{SomeClass(),std::mutex(),std::string()}; ... auto [ mtx,sc,str ] = get_class_and_mutex();
我将假设你已经return
为编译语句做了必要的补充.
鉴于此,函数中的构造将直接初始化HIDDEN_VALUE
返回站点.并且聚合的每个成员将由prvalues直接初始化,因此不会发生复制.
归档时间: |
|
查看次数: |
5231 次 |
最近记录: |