首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >科技促进发展方案的实施:

科技促进发展方案的实施:
EN

Stack Overflow用户
提问于 2014-12-16 09:32:48
回答 5查看 14.3K关注 0票数 54

我正在阅读新C++概述(C++11/14) (仅限PDF格式),在幻灯片288中给出了std::forward的实现

代码语言:javascript
复制
template<typename T>                // For lvalues (T is T&),
T&& std::forward(T&& param)         // take/return lvalue refs.
{                                   // For rvalues (T is T),
    return static_cast<T&&>(param); // take/return rvalue refs.
}

然后在文本中给出了另一种表示:

通常的std::forward实现是:

代码语言:javascript
复制
template<typename T>
struct identity {
    typedef T type;
};
template<typename T>
T&& forward(typename identity<T>::type&& param)
{
    return static_cast<identity<T>::type&&>(param);
}

有什么关系?为什么后者是通常的实现?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2014-12-16 09:36:10

第一个问题是,您可以编写std::forward(x),因为它总是生成lvalue引用,所以它不会执行您想要的操作。

第二种情况下的参数是一个非推导的上下文,防止了模板参数的自动推导。这迫使您编写std::forward<T>(x),这是正确的做法。

另外,第二个重载的参数类型应该是typename identity<T>::type&,因为惯用std::forward的输入总是一个lvalue。

编辑:标准实际上要求一个与此签名等价的签名(顺便说一句,这正是libc++所拥有的):

代码语言:javascript
复制
template <class T> T&& forward(typename remove_reference<T>::type& t) noexcept;
template <class T> T&& forward(typename remove_reference<T>::type&& t) noexcept;
票数 42
EN

Stack Overflow用户

发布于 2014-12-16 09:50:15

libc++中的实现使用std::remove_reference和两个重载。下面是源代码(删除了一些宏之后):

代码语言:javascript
复制
template <class T>
inline T&& forward(typename std::remove_reference<T>::type& t) noexcept
{
    return static_cast<T&&>(t);
}

template <class T>
inline T&& forward(typename std::remove_reference<T>::type&& t) noexcept
{
    static_assert(!std::is_lvalue_reference<T>::value,
                  "Can not forward an rvalue as an lvalue.");
    return static_cast<T&&>(t);
}

但请注意,在C++14中,std::forwardconstexpr

票数 23
EN

Stack Overflow用户

发布于 2016-07-11 02:04:47

第一个案例,正如Sebastian所说,总是会给你一个无价值的参考。原因是参数中的rvalue引用将作为lvalue引用传递,而参数T&&类型是通用参考而不是rvalue引用。

实际上,如果第一种情况是正确的,我们甚至不再需要forward了。下面是一个演示如何传递通用参考参数的实验。

代码语言:javascript
复制
template <typename T, typename U>
void g(T&& t, U&& u)
{
    std::cout << "t is lvalue ref: "
              << std::is_lvalue_reference<decltype(t)>::value << std::endl; // 1
    std::cout << "t is rvalue ref: "
              << std::is_rvalue_reference<decltype(t)>::value << std::endl; // 0
    std::cout << "u is lvalue ref: "
              << std::is_lvalue_reference<decltype(u)>::value << std::endl; // 1
    std::cout << "u is rvalue ref: "
              << std::is_rvalue_reference<decltype(u)>::value << std::endl; // 0
}

template <typename T, typename U>
void f(T&& t, U&& u)
{
    std::cout << "t is lvalue ref: "
              << std::is_lvalue_reference<decltype(t)>::value << std::endl; // 1
    std::cout << "t is rvalue ref: "
              << std::is_rvalue_reference<decltype(t)>::value << std::endl; // 0
    std::cout << "u is lvalue ref: "
              << std::is_lvalue_reference<decltype(u)>::value << std::endl; // 0
    std::cout << "u is rvalue ref: "
              << std::is_rvalue_reference<decltype(u)>::value << std::endl; // 1

    g(t, u);
}

int main()
{
    std::unique_ptr<int> t;
    f(t, std::unique_ptr<int>());
    return 0;
}

程序证明,tuf传递到g都是lvalue引用,尽管uf中的rvalue引用。因此,在第一种情况下,forward的参数没有机会成为rvalue引用。

identity用于将参数类型从通用引用更改为rvalue引用(正如Redl所提到的,使用std::remove_reference更精确)。但是,这种更改使得模板类型的推断不再可能,因此forward的类型参数是强制性的,因此我们将编写forward<T>(t)

但是问题中的第二种情况也是不正确的,正如Redl所提到的,正确的方法是重载,其参数是lvalue引用。

我能找到的最直接的实现是

代码语言:javascript
复制
template <typename T>
T&& forward(typename identity<T>::type& param)
{
    return static_cast<T&&>(param);
}

例如,它适用于通用引用。

代码语言:javascript
复制
template <typename T, typename U>
void f(T&& t, U&& u)
{
    ::forward<T>(t);
    ::forward<U>(u);
}

std::unique_ptr<int> t;
f(t, std::unique_ptr<int>());
// deduction in f:
//   T = unique_ptr&, decltype(t) = unique_ptr&
//   U = unique_ptr, decltype(u) = unique_ptr&& (but treated as an lvalue reference)
// specialization of forward:
//   forward<T> = forward<unique_ptr&>, param type = unique_ptr&
//                                      return type = unique_ptr&
//   forward<U> = forward<unique_ptr>,  param type = unique_ptr&
//                                      return type = unique_ptr&&
票数 13
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27501400

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档