如何声明接受转发引用并返回引用或副本的功能模板 [英] How to declare a function template that accepts forwarding reference and returns either a reference or a copy
问题描述
我试图声明一个函数模板,该函数模板在传递左值时应接受并返回非常量引用,但在传递右值时应返回兼容RVO的本地副本:
< template?>
? StringReplace(?str,?from,?to);
我希望模板生成以下签名:
-
用于非常量左值
std :: string& StringReplace(std :: string& str,const std :: string& from,const std :: string& to);
-
表示常量值
std :: string StringReplace(const std :: string& str,const std :: string& from,const std :: string& to);
-
用于非常量右值
std :: string StringReplace(std :: string& ;, const std :: string& ;, const std :: string&)
-
用于常量值
std: :string StringReplace(const std :: string&& ;, const std :: string& ;, const std :: string&)
-
用于字符串文字
std :: string StringReplace(std :: string& ;, const std :: string& ;, const std :: string&)
是否可以使用单个模板指定一个?
也许标准库中有一个函数或方法通过使用一个或多个我应该用作参考的模板来达到相同的结果?
有关最终版本,请参见我的答案。
我相信这个基本想法可以满足您的要求:
template< typename Str>
Str foo(Str&&str)
{
return std :: forward< Str>(str);
}
如果参数是非常量左值,则 Str
会被扣除为 S&
,而远期也将被解析为 S&
。 / p>
如果参数为右值,则将 Str
推导为 S
,返回值是从参数复制/移动构造的。
如果显式给出了模板参数,则转发引用的推论被抑制,您必须确保给出 S&
如果函数参数是 S&
可以直接绑定的左值;否则为 S
。
通过引用传递的函数参数从来没有RVO;例如假设调用上下文是 std :: string s = StringReplace(std :: string( foo),x,Y);
,此时编译器无法知道使用与 s
相同的内存空间作为临时字符串。最好的办法就是移动构造返回值。
注意:原始代码试图为所有3个参数推导 Str
,这会导致推论冲突。您应该推断出转发参考,对于其他两个参考,请使用非推断上下文或不同的模板参数。例如:
template< typename Str,typename T>
Str StringReplace(Str& str,T const& from,T const& to)
或使用 CRef
,如super的答案所示(如果参数出现在 ::
)。
I'm trying to declare a function template that should accept and return a non-const reference when passed an lvalue, but return an RVO-compatible local copy when passed an rvalue:
<template ?>
? StringReplace(? str, ? from, ? to);
I want template to generate the following signatures:
for non-const lvalues
std::string& StringReplace(std::string& str, const std::string& from, const std::string& to);
for const lvalues
std::string StringReplace(const std::string& str, const std::string& from, const std::string& to);
for non-const rvalues
std::string StringReplace(std::string&&, const std::string&, const std::string&)
for const rvalues
std::string StringReplace(const std::string&&, const std::string&, const std::string&)
for string literal
std::string StringReplace(std::string&&, const std::string&, const std::string&)
Is it possible to specify one using single template? Perhaps there is a function or method in the standard library that achieves the same result by using one or multiple templates I should use as a reference?
See my answer for the version I ended up with.
I believe this basic idea meets your requirements:
template<typename Str>
Str foo(Str&& str)
{
return std::forward<Str>(str);
}
If the argument is a non-const lvalue, then Str
is deducted to S&
and the forward resolves to S&
also.
If the argument is an rvalue then Str
is deduced to S
, and the return value is copy/move-constructed from the argument.
If you explicitly give the template argument, then forwarding reference deduction is suppressed and you would have to make sure to give S&
if the function argument is an lvalue that S&
can bind directly to; or S
otherwise.
There is never RVO for a function parameter passed by reference; e.g. suppose the calling context were std::string s = StringReplace( std::string("foo"), x, Y);
, the compiler cannot know at this point to use the same memory space for s
as the temporary string. The best you can do is to move-construct the return value.
Note: Your original code tries to deduce Str
for all 3 arguments, this causes deduction conflicts. You should deduce the forwarding reference and for the other two, either use a non-deduced context or a different template parameter. For example:
template<typename Str, typename T>
Str StringReplace(Str&& str, T const& from, T const& to)
or use the CRef
as shown in super's answer (deduction is disabled if the parameter appears to the left of ::
).
这篇关于如何声明接受转发引用并返回引用或副本的功能模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!