你能不能将C ++ RValue引用参数标记为const

时间:2013-02-07 01:31:42

标签: c++ c++11 const rvalue-reference perfect-forwarding

我一直在使用模板工厂函数来使用(和理解)std :: forward来支持rvalues和移动语义。我通常用于模板类的样板工厂函数始终将参数标记为const:

#include <iostream>
#include <utility>

template<typename T, typename U>
struct MyPair{
    MyPair(const T& t, const U& u):t(t),u(u){};

    T t;
    U u;
};

template<typename T, typename U>
std::ostream& operator<<(std::ostream& os, const MyPair<T,U>& pair){
    os << "(" << pair.t << ")=>" << pair.u;
    return os;
}

template<typename T, typename U>
MyPair<T,U> MakeMyPair(const T& t, const U& u){
    return MyPair<T,U>(t,u);
}

using namespace std;
int main(int argc, char *argv[]) {    

    auto no_forward = MakeMyPair(num, num);
    std::cout << no_forward << std::endl;

    auto no_forward2 = MakeMyPair(100, false);
    std::cout << no_forward2 << std::endl;
}

按预期编译。最初我转换MakeMyPair也将参数作为const传递,但这不会在我的Mac上使用XCode 4.6进行编译:

//$ clang --version
//Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn)
//Target: x86_64-apple-darwin12.2.0
//Thread model: posix


template<typename T, typename U>
MyPair<T,U> MakeMyPair_Forward(const T&& t, const U&& u){
    return MyPair<T,U>(std::forward<const T>(t),std::forward<const U>(u));
}

int main(int argc, char *argv[]) { 
    int num = 37;
    auto anotherPair = MakeMyPair_Forward(num, true); //This won't work

    auto allRvalues = MakeMyPair_Forward(73, false);   //will compile 
    std::cout << allRvalues  << std::endl;
}
  

没有匹配函数来调用'MakeMyPair_Forward'候选人   函数[与T = int,U = bool]不可行:没有已知的转换   'int'到'const int&amp;&amp;'第一个参数

这从http://en.cppreference.com/w/cpp/utility/forward开始是有道理的,其中推导出const并且我传递了左值。

  
      
  • 如果对wrapper()的调用传递了一个rvalue std :: string,则T被推导为std :: string(不是std :: string&amp;,const std :: string&amp;,或者   std :: string&amp;&amp;)和std :: forward确保rvalue引用   传给了foo。
  •   
  • 如果对wrapper()的调用传递了const lvalue std :: string,那么T被推导为const std :: string&amp;,并且std :: forward确保了一个const   左值引用传递给foo。
  •   
  • 如果对wrapper()的调用传递了非const左值std :: string,则T被推导为std :: string&amp;,并且std :: forward确保非const   左值引用传递给foo。
  •   

使用rvalues和lvalues删除const可以正常工作。只有将rvalues作为类型传递才能在MakeMyPair_Forward的参数上使用const。

//This works for rvalues and lvalues
template<typename T, typename U>
MyPair<T,U> MakeMyPair_Forward(T&& t, U&& u){
    return MyPair<T,U>(std::forward<const T>(t),std::forward<const U>(u));
}

所以,问题。将rvalue引用标记为const作为参数传递时是否有意义?这不像我可以改变右值,它只是暂时的。在完成并修复我的代码后,我对使用const编译时有点惊讶。为什么要将rvalue参数标记为const?重点是只提供一个采用rvalues的API吗?如果是这样,你会不会使用类型特征来阻止左值引用? https://stackoverflow.com/a/7863645/620304

感谢。

2 个答案:

答案 0 :(得分:15)

  

所以,问题。标记右值引用是否有意义?   作为参数传递时为const?

这是在C ++ 11标准中完成的一个地方:

template <class T> reference_wrapper<T> ref(T&) noexcept;
template <class T> reference_wrapper<const T> cref(const T&) noexcept;
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;

即。 const T&&用于捕获所有rvalues,const或not,并将它们抛到编译时错误,同时允许lvalues,甚至const lvalues绑定和工作。

现在也可以使用T&&enable_if约束来完成此操作。但是,如果在过去的几十年中C ++已经教会我们一件事:不要在语言设计中烧掉任何桥梁。 C ++程序员经常会找到一种聪明的方法来使用最初被认为无用的语言功能。正是本着这种精神,const T&&被留下作为合法选择。

答案 1 :(得分:1)

另一种可能的用例是 smart pointers constructor from raw pointer ,例如,该语言不是 ,例如:

// this is NOT the actual ctor in the language but could have been
// see explanation in above link
unique_ptr(T* const&& p) : ptr{p} {}