相关疑难解决方法(0)

为什么"通用引用"与rvalue引用具有相同的语法?

我刚刚对那些(相当)新功能进行了一些研究,我想知道为什么C++委员会决定为它们引入相同的语法?似乎开发人员不必浪费一些时间来理解它是如何工作的,并且一个解决方案让我们考虑进一步的问题.在我的情况下,它从问题开始,可以简化为:

#include <iostream>

template <typename T>
void f(T& a)
{
    std::cout << "f(T& a) for lvalues\n";
}

template <typename T>
void f(T&& a)
{
    std::cout << "f(T&& a) for rvalues\n";
}

int main()
{
    int a;
    f(a);
    f(int());

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我首先在VS2013上编译它,它按照我的预期工作,结果如下:

f(T& a) for lvalues
f(T&& a) for rvalues
Run Code Online (Sandbox Code Playgroud)

但有一个可疑的事情:intellisense强调了f(a).我做了一些研究,我明白这是因为类型崩溃(Scott Meyers将它命名为通用引用),所以我想知道g ++对它的看法.当然它没有编译.微软实现他们的编译器以更直观的方式工作是非常好的,但我不确定它是否符合标准,是否应该在IDE中存在这种差异(编译器与智能感知,但实际上可能存在在某种程度上是有道理的).好的,回到问题所在.我用这种方式解决了它:

template <typename T>
void f(T& a)
{
    std::cout << "f(T& a) for lvalues\n";
}

template <typename T>
void f(const T&& a)
{
    std::cout << "f(T&& a) for …
Run Code Online (Sandbox Code Playgroud)

c++ reference rvalue universal c++11

33
推荐指数
3
解决办法
7968
查看次数

是否有使用prvalue的std :: forward的用例?

最常见的用法std::forward是,完美地转发转发(通用)引用,例如

template<typename T>
void f(T&& param)
{
    g(std::forward<T>(param)); // perfect forward to g
}
Run Code Online (Sandbox Code Playgroud)

param是一个lvalue,并std::forward最终将它转换为右值或左值,具体取决于与它有关的参数.

看一下cppreference.com定义,std::forward我发现还有一个rvalue重载

template< class T >
T&& forward( typename std::remove_reference<T>::type&& t );
Run Code Online (Sandbox Code Playgroud)

任何人都可以给我任何rvalue超载的理由吗?我看不到任何用例.如果你想将一个右值传递给一个函数,你可以按原样传递它,不需要std::forward在它上面应用.

这与std::move我不同,我明白为什么人们也想要一个rvalue重载:你可能会处理通用代码,在这些代码中你不知道你传递了什么,你想要无条件支持移动语义,请参阅例如为什么std ::移动采取普遍参考?.

编辑为了澄清这个问题,我问为什么从这里需要重载(2),以及它的用例.

c++ rvalue-reference move-semantics c++11

25
推荐指数
1
解决办法
844
查看次数

为什么用std :: forward禁用模板参数推导?

在VS2010中,std :: forward定义如下:

template<class _Ty> inline
_Ty&& forward(typename identity<_Ty>::type& _Arg)
{   // forward _Arg, given explicitly specified type parameter
    return ((_Ty&&)_Arg);
}
Run Code Online (Sandbox Code Playgroud)

identity似乎仅用于禁用模板参数推断.在这种情况下故意禁用它有什么意义?

c++ stl visual-studio-2010 c++11

24
推荐指数
2
解决办法
4944
查看次数

std :: forward()的右值引用重载的目的是什么?

我正在尝试完美转发,发现 std::forward()需要两个重载:

过载 1:

template <typename T>
inline T&& forward(typename 
std::remove_reference<T>::type& t) noexcept
{
    return static_cast<T&&>(t);
}
Run Code Online (Sandbox Code Playgroud)

重载nr.2:

template <typename 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);
}
Run Code Online (Sandbox Code Playgroud)

现在,完美转发的典型场景是

template <typename T>
void wrapper(T&& e)
{
    wrapped(forward<T>(e));
}
Run Code Online (Sandbox Code Playgroud)

当然,您知道何时wrapper()实例化T取决于传递给它的参数是左值还是右值。如果它是type的左值UT则推导为U&。如果是右值,T则推导为U

无论如何-在-的范围内wrapper()- e是一个左值,因此它始终使用的第一个重载std::forward()

现在我的问题是:

使用(需要)第二重载的有效方案是什么?

c++ perfect-forwarding c++11 c++14 c++17

16
推荐指数
1
解决办法
409
查看次数

为什么std :: forward有两个重载?

鉴于以下参考折叠规则

  • T& & - > T&
  • T&& & - > T&
  • T& && - > T&
  • T&& && - > T&&

第三和第四条规则意味着T(ref qualifer) &&身份转变,即T&停留在T&T&&保持在T&&.为什么我们有两个重载std::forward?以下定义无法满足所有目的吗?

template <typename T, typename = std::enable_if_t<!std::is_const<T>::value>>
T&& forward(const typename std::remove_reference<T>::type& val) {
    return static_cast<T&&>(const_cast<T&&>(val));
}
Run Code Online (Sandbox Code Playgroud)

这里服务的唯一目的const std::remove_reference<T>&是不复制.并且enable_if有助于确保仅在非const值上调用该函数.我不完全确定是否const_cast需要它,因为它不是引用本身的const.

由于forward总是使用显式模板参数调用,因此我们需要考虑两种情况:

  1. forward<Type&>(val)这里Tin 的类型forward将是T&,因此返回类型将是身份转换T&
  2. forward<Type&&>(val)这里Tin 的类型forward将是T&& …

c++ reference rvalue perfect-forwarding c++11

13
推荐指数
1
解决办法
772
查看次数

std::forward 的第二次重载(cppreference.com 上的示例)

我知道第二次过载std::forward

template< class T >
constexpr T&& forward( std::remove_reference_t<T>&& t ) noexcept;
Run Code Online (Sandbox Code Playgroud)

用于右值(如 Howard Hinnant 在他的回答中所述:How does std::forward receive the right argument?

cppreference.com上有一个使用此重载的示例( Praetorian 的How does std::forward receive the right argument?中也提到了这一点):

  1. 将右值作为右值转发,并禁止将右值作为左值转发 此重载使得可以将表达式(例如函数调用)的结果(可能是右值或左值)转发为转发引用参数的原始值类别。

例如,如果包装器不仅转发其参数,还调用该参数的成员函数,并转发其结果:

// transforming wrapper 
template<class T>
void wrapper(T&& arg)
{
    foo(forward<decltype(forward<T>(arg).get())>(forward<T>(arg).get()));
}
Run Code Online (Sandbox Code Playgroud)

其中 arg 的类型可以是

struct Arg
{
    int i = 1;
    int  get() && { return i; } // call to this overload is rvalue
    int& get() &  { …
Run Code Online (Sandbox Code Playgroud)

c++ perfect-forwarding c++11

5
推荐指数
1
解决办法
396
查看次数