为什么一个完美的转发函数必须模板化? [英] Why does a perfect forwarding function have to be templated?

查看:91
本文介绍了为什么一个完美的转发函数必须模板化?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么以下代码有效:

 模板< typename T1& 
void foo(T1&& arg){bar(std :: forward< T1>(arg)); }

std :: string str =Hello World;
foo(str); //有效即使str是一个左值
foo(std :: string(Hello World)); //有效,因为字面值是右值

但不是:


$ b b

  void foo(std :: string&& arg){bar(std :: forward< std :: string>(arg)); } 

std :: string str =Hello World;
foo(str); //无效,str不能转换为右值
foo(std :: string(Hello World)); // Valid

为什么示例2中的左值不能以与它相同的方式解析在示例1中?



此外,为什么标准感觉需要提供std :: forward中的参数类型和简单的deducing呢?如果这不是一个标准的东西,只是我的编译器,我使用msvc10,这将解释appy appy appy appy appy appy appy appy appy appy appy appy appy appy appy appy appy appy appy appy appy appy appy appy

感谢



编辑1:将文字Hello World更改为std

解决方案

首先,了解此以获得转发的完整概念。 (是的,我将其他大部分的答复委托给其他人。)



总而言之,转移意味着左值保持左值,右值保持右值。你不能用单一类型,所以你需要两个。因此,对于每个转发的参数,您需要两个版本的参数,这需要函数的2个 N 组合。您可以编写函数的所有组合,但如果您使用模板,那么会根据需要为您生成这些不同的组合。






如果您尝试优化副本和移动,例如:

  struct foo 
{
foo(const T& pX,const U& pY,const V& pZ):
x(pX),
y(pY),
z
{}

foo(T&& pX,const U& pY,const V& pZ):
x(std :: move(pX)),$ b $由(pY),
z(pZ)
{}

//等? :(

T x;
U y;
V z;
};

然后你应该停止并以这种方式做:

  struct foo 
{
//这些是复制构造或移动构造,
//但之后,他们都是你的移动到
//(也就是:
x(std :: move(pX)),
y(std:move-pos)。
foo(T pX,U pY,V pZ) :move(pY)),
z(std :: move(pZ))
{}

T x;
U y;
V z ;
};

您只需要一个构造函数。指南 :如果你需要你自己的数据副本,在参数列表中做这个副本;这使决定复制或移动到调用者和编译器。


Why is the following code valid:

template<typename T1>
void foo(T1 &&arg) { bar(std::forward<T1>(arg)); }

std::string str = "Hello World";
foo(str); // Valid even though str is an lvalue
foo(std::string("Hello World")); // Valid because literal is rvalue

But not:

void foo(std::string &&arg) { bar(std::forward<std::string>(arg)); }

std::string str = "Hello World";
foo(str); // Invalid, str is not convertible to an rvalue
foo(std::string("Hello World")); // Valid

Why doesn't the lvalue in example 2 get resolved in the same manner that it does in example 1?

Also, why does the standard feel it important to need to provide the argument type in std::forward versus simple deducing it? Simply calling forward is showing intention, regardless of the type.

If this isn't a standard thing and just my compiler, I am using msvc10, which would explain the crappy C++11 support.

Thanks

Edit 1: Changed the literal "Hello World" to be std::string("Hello World") to make an rvalue.

解决方案

First of all, read this to get a full idea of forwarding. (Yes, I'm delegating most of this answer elsewhere.)

To summarize, forwarding means that lvalues stay lvalues and rvalues stay rvalues. You can't do that with a single type, so you need two. So for each forwarded argument, you need two versions for that argument, which requires 2N combinations total for the function. You could code all the combinations of the function, but if you use templates then those various combinations are generated for you as needed.


If you're trying to optimize copies and moves, such as in:

struct foo
{
    foo(const T& pX, const U& pY, const V& pZ) :
    x(pX),
    y(pY),
    z(pZ)
    {}

    foo(T&& pX, const U& pY, const V& pZ) :
    x(std::move(pX)),
    y(pY),
    z(pZ)
    {}

    // etc.? :(

    T x;
    U y;
    V z;
};

Then you should stop and do it this way:

struct foo
{
    // these are either copy-constructed or move-constructed,
    // but after that they're all yours to move to wherever
    // (that is, either: copy->move, or move->move)
    foo(T pX, U pY, V pZ) :
    x(std::move(pX)),
    y(std::move(pY)),
    z(std::move(pZ))
    {}

    T x;
    U y;
    V z;
};

You only need one constructor. Guideline: if you need your own copy of the data, make that copy in the parameter list; this enables the decision to copy or move up to the caller and compiler.

这篇关于为什么一个完美的转发函数必须模板化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆