为什么一个完美的转发功能必须模板化?

发布于 2024-12-19 00:43:07 字数 911 浏览 1 评论 0原文

为什么以下代码有效:

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

但无效:

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

为什么示例 2 中的左值没有以与示例 1 中相同的方式解析?

另外,为什么标准认为需要在 std::forward中提供参数类型而不是简单地推导它很重要?无论类型如何,只需调用 forward 即可显示意图。

如果这不是一个标准的东西而只是我的编译器,那么我使用的是 msvc10,这可以解释糟糕的 C++11 支持。

编辑 1:将文字 "Hello World" 更改为 std::string("Hello World") 以创建右值。

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<T> 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.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

向地狱狂奔 2024-12-26 00:43:07

首先,阅读本文以全面了解转发。 (是的,我将大部分答案委托给其他地方。)

总而言之,转发意味着左值保持左值,右值保持右值。您无法使用单一类型来做到这一点,因此您需要两种。因此,对于每个转发的参数,您需要该参数的两个版本,这需要该函数总共 2N 个组合。您可以对函数的所有组合进行编码,但是如果您使用模板,那么系统会根据需要为您生成这些不同的组合。


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

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;
};

那么您应该停止并这样做:

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;
};

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文