简体   繁体   English

您是否曾将 C++ RValue 引用参数标记为 const

[英]Would you ever mark a C++ RValue reference parameter as const

I've been switching Template Factory functions to use (and understand) std::forward to support rvalues and move semantics.我一直在切换模板工厂函数以使用(并理解)std::forward 来支持右值和移动语义。 My usual boilerplate factory functions for template classes have always marked the parameters as const:我通常用于模板类的样板工厂函数总是将参数标记为 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;
}

Compiles as expected.按预期编译。 Initially I converted MakeMyPair to also pass the parameters as const but this won't compile on my Mac using XCode 4.6:最初我将 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;
}

No matching function for call to 'MakeMyPair_Forward' Candidate function [with T = int, U = bool] not viable: no known conversion from 'int' to 'const int &&' for 1st argument没有用于调用“MakeMyPair_Forward”候选函数的匹配函数 [with T = int, U = bool] 不可行:第一个参数没有从“int”到“const int &&”的已知转换

This makes sense from http://en.cppreference.com/w/cpp/utility/forward which states const is deduced and I'm passing lvalue.这从http://en.cppreference.com/w/cpp/utility/forward中是有道理的,它指出 const 是推导出来的,我正在传递左值。

  • If a call to wrapper() passes an rvalue std::string, then T is deduced to std::string (not std::string&, const std::string&, or std::string&&), and std::forward ensures that an rvalue reference is passed to foo.如果对 wrapper() 的调用传递右值 std::string,则 T 被推导为 std::string(不是 std::string&、const std::string& 或 std::string&&),并且 std::forward 确保将右值引用传递给 foo。
  • If a call to wrapper() passes a const lvalue std::string, then T is deduced to const std::string&, and std::forward ensures that a const lvalue reference is passed to foo.如果对 wrapper() 的调用传递了一个 const 左值 std::string,则 T 被推导为 const std::string&,并且 std::forward 确保将一个 const 左值引用传递给 foo。
  • If a call to wrapper() passes a non-const lvalue std::string, then T is deduced to std::string&, and std::forward ensures that a non-const lvalue reference is passed to foo.如果对 wrapper() 的调用传递了一个非常量左值 std::string,则 T 被推导为 std::string&,并且 std::forward 确保将非常量左值引用传递给 foo。

Removing const works as I want with rvalues and lvalues.删除 const 可以像我想要的那样使用右值和左值。 Only passing rvalues as types will work with const on MakeMyPair_Forward's parameters.只有将右值作为类型传递才能在 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));
}

So, the question.所以,问题。 Does it make any sense to mark an rvalue reference as const when passing as a parameter?作为参数传递时,将右值引用标记为 const 是否有意义? It's not like I can change an rvalue, it's just temporary.我不能改变右值,这只是暂时的。 I was a bit surprised it compiled with the const after working through and fixing my code.在完成并修复我的代码后,我有点惊讶它用 const 编译。 Why would you mark an rvalue parameter as const?为什么要将右值参数标记为 const? Would the point be to only provide an API that takes rvalues?重点是只提供一个接受右值的 API 吗? If so, wouldn't you use type traits instead to prevent lvalue references?如果是这样,您会不会使用类型特征来防止左值引用? https://stackoverflow.com/a/7863645/620304 https://stackoverflow.com/a/7863645/620304

Thanks.谢谢。

So, the question.所以,问题。 Does it make any sense to mark an rvalue reference as const when passing as a parameter?作为参数传递时,将右值引用标记为 const 是否有意义?

Here is one place this is done in the C++11 standard:这是在 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;

Ie A const T&& is used to capture all rvalues, const or not, and toss them to a compile-time error, while allowing lvalues, even const lvalues to bind and work.const T&&用于捕获所有右值,无论是否为 const,并将它们扔给编译时错误,同时允许左值,甚至是const左值绑定和工作。

Now this could also probably be done with T&& and an enable_if constraint.现在这也可以通过T&&enable_if约束来完成。 But if there's one thing that C++ has taught us over the past few decades: Don't burn any bridges in language design.但是,如果 C++ 在过去几十年中教会了我们一件事:不要在语言设计中烧掉任何桥梁。 The C++ programmer will often find a clever way to use a language feature that was initially thought useless. C++ 程序员经常会找到一种聪明的方法来使用最初被认为无用的语言功能。 And it is in that spirit that const T&& was left as a legal option.正是本着这种精神, const T&&被保留为合法选项。

Another possible use case, that was not taken by the language, but could have been, is smart pointers constructor from raw pointer , eg:另一个可能的用例,不是被语言采用,但可能是,是来自原始指针的智能指针构造函数,例如:

// 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} {}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM