首页 文章

您是否可以将C RValue参考参数标记为const

提问于
浏览
7

我一直在切换模板工厂函数来使用(和理解)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 &&'的已知转换

这从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));
}

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

谢谢 .

1 回答

  • 12

    那么,问题 . 将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;
    

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

    现在,这也可以通过 T&&enable_if 约束完成 . 但如果在语言设计中烧掉任何桥梁 . C程序员经常会找到一种聪明的方法来使用最初被认为无用的语言功能 . 正是出于这种精神, const T&& 才被视为合法选择 .

相关问题