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

Joe*_*oel 9 c++ const rvalue-reference perfect-forwarding c++11

我一直在切换模板工厂函数来使用(和理解)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;
}
Run Code Online (Sandbox Code Playgroud)

按预期编译.最初,我将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;
}
Run Code Online (Sandbox Code Playgroud)

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

http://en.cppreference.com/w/cpp/utility/forward中可以看出这是有意义的,其中推导出const并且我传递了左值.

  • 如果对wrapper()的调用传递了一个rvalue std :: string,则T被推导为std :: string(不是std :: string&,const std :: string&或std :: string &&),std :: forward确保将右值引用传递给foo.
  • 如果对wrapper()的调用传递了const lvalue std :: string,那么T被推导为const std :: string&,而std :: forward确保将const值引用传递给foo.
  • 如果对wrapper()的调用传递非const左值std :: string,则T被推导为std :: string&,而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));
}
Run Code Online (Sandbox Code Playgroud)

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

谢谢.

How*_*ant 16

所以,问题.将rvalue引用标记为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;
Run Code Online (Sandbox Code Playgroud)

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

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

  • 只是fyi,那些不是构造函数,而是删除了命名空间范围函数.而****在C++ 11中是一个非常酷的新东西,一种禁用非成员函数的方法!:-)以前我们能做的最好的是声明而不是定义它,将错误延迟到链接时间. (2认同)