简体   繁体   English

rvalue或lvalue(const)引用参数

[英]rvalue or lvalue (const) reference parameter

I want to pass a parameter(s) (of some concrete type, say int ) to the member function by r- or l- value (const) reference. 我想通过r-或l-值(const)引用将参数(一些具体类型,比如int )传递给成员函数。 My solution is: 我的解决方案是:

#include <type_traits>
#include <utility>

struct F
{
    using desired_parameter_type = int;

    template< typename X, typename = typename std::enable_if< std::is_same< typename std::decay< X >::type, desired_parameter_type >::value >::type >
    void operator () (X && x) const
    {
        // or even static_assert(std::is_same< typename std::decay< X >::type, desired_parameter_type >::value, "");
        std::forward< X >(x); // something useful
    }
};

Another exaple is here http://pastebin.com/9kgHmsVC . 另一个例子是http://pastebin.com/9kgHmsVC

But it is too verbose. 但它太冗长了。 How to do it in a simpler way? 如何以更简单的方式做到这一点?

Maybe I should use the superposition of std::remove_reference and std::remove_const instead of std::decay , but there is just a simplification here. 也许我应该使用std::remove_referencestd::remove_const的叠加而不是std::decay ,但这里只是简化。

If I understand your question correctly, you wish to have a single function whose parameter is either an rvalue reference (in case an rvalue is provided) or an lvalue reference to const (in case an lvalue is provided). 如果我正确理解你的问题,你希望有一个函数,其参数是一个右值引用(如果提供了右值)或一个左值引用const (如果提供了左值)。

But what would this function do? 但是这个功能会做什么? Well, since it must be able to handle both cases, including the case where an lvalue is provided, it cannot modify its input (at least not the one bound to the x parameter) - if it did, it would violate the semantics of the const reference. 好吧,因为它必须能够处理这两种情况,包括提供左值的情况,它不能修改它的输入(至少不是绑定到x参数的那个) - 如果确实如此,它将违反语义const参考。

But then again, if it cannot alter the state of the parameter, there is no reason for allowing an rvalue reference: rather let x be an lvalue-reference to const all the time. 但话又说回来,如果它不能改变参数的状态,就没有理由允许rvalue引用:而是让x一直是对const的lvalue引用。 lvalue references to const can bind to rvalues, so you will be allowed to pass both rvalues and lvalues. const左值引用可以绑定到rvalues,因此您将被允许传递rvalues和lvalues。

If the semantics of the function is different based on what is passed, then I would say it makes more sense to write two such functions: one that takes an rvalue reference and one that takes an lvalue reference to const . 如果函数的语义根据传递的内容而不同,那么我会说编写两个这样的函数更有意义:一个采用右值引用,另一个采用左值引用const

As Andy has mentioned, the important thing here is what you could actually do inside your function which would make sense. 正如Andy所提到的,重要的是你在函数中实际可以做的事情是有意义的。

  • You can forward arguments to another function. 您可以将参数转发给另一个函数。 In this case, using a template doesn't matter, because if the wrong parameter type is given it will still produce a compile error (wrong types sent to second function). 在这种情况下,使用模板并不重要,因为如果给出了错误的参数类型,它仍然会产生编译错误(错误的类型发送到第二个函数)。 You can use template <typename T> blah (T && x) . 您可以使用template <typename T> blah (T && x)
  • Anything else would require you to write different code depending on whether it is an r- or l- value reference, so you'll need to write 2 functions anyway: blah (const int & x) and blah (int && x) . 其他任何东西都要求你根据它是r值还是l值引用来编写不同的代码,所以你需要编写2个函数: blah (const int & x)blah (int && x)

I assume you must be attempting the first option and you're trying to make any potential compiler errors more user-friendly. 我假设您必须尝试第一个选项,并且您尝试使任何潜在的编译器错误更加用户友好。 Well, I'd say it's not worth it; 好吧,我说这不值得; the programmer will still see a "called by…" list in the output of any decent compiler. 程序员仍然会在任何体面的编译器的输出中看到“被...调用”列表。

Actually, this is a very good question. 实际上,这是一个非常好的问题。 So far I have also been using the universal reference trick plus the enable_if hammer. 到目前为止,我一直在使用通用引用技巧和enable_if锤。 Here I present a solution that doesn't make use of templates and uses lvalue cast as an alternative. 在这里,我提出了一个不使用模板的解决方案,并使用左值转换作为替代方案。

What follows is a real example where the situation arises using the known example of inplace ofstream usage that is not possible (or very hard) in C++98 (I use ostringstream in the example to make it more clear). 以下是其中的情况出现就地使用的众所周知的例子一个真实的例子ofstream使用中这是不可能的(或很难)C ++ 98(我用ostringstream在本例中,使之更加清楚)。

First you will see a function on lvalue reference as often seen in C++98. 首先,您将看到一个关于左值引用的函数,如C ++ 98中常见的那样。

#include<iostream>
#include<sstream>
struct A{int impl_;};

std::ostringstream& operator<<(std::ostringstream& oss, A const& a){
    oss << "A(" << a.impl_ << ")"; // possibly much longer code.
    return oss;
}
// naive C++11 rvalue overload without using templates
std::ostringstream& operator<<(std::ostringstream&& oss, A const& a){
    oss << "A(" << a.impl_ << ")"; // ok, but there is code repetition.
    return oss;
}

int main() {

    A a{2};
    {// C++98 way
        std::ostringstream oss;
        oss << a;
        std::cout << oss.str() << std::endl; // prints "A(2)", ok"
    }
    {// possible with C++11, because of the rvalue overload
        std::cout << (std::ostringstream() << a).str() << std::endl; //prints "A(2)", ok
    }
}

As you can see in C++11 we can achieve what we can't in C++98. 正如您在C ++ 11中看到的那样,我们可以实现C ++ 98中无法实现的功能。 That is to make use of the ostringstream (or ofstream ) inplace. 那就是使用ostringstream (或ofstream )。 Now comes the OP question, the two overloads look very similar, can both be joined in one? 现在是OP问题,两个重载看起来非常相似,可以加在一起吗?

One option is to use universal reference ( Ostream&& ), and optionally with enable_if to constrain the type. 一种选择是使用通用引用( Ostream&& ),并可选择使用enable_if来约束类型。 Not very elegant. 不是很优雅。

What I found by using this "real world" example is that if want to use the same code for lvalue ref and rvalue ref is because probably you can convert one to the other! 我通过使用这个“真实世界”的例子发现,如果想为lvalue ref和rvalue ref使用相同的代码是因为可能你可以将一个转换为另一个!

std::ostringstream& operator<<(std::ostringstream&& oss, A const& a){
    return operator<<(oss, a);
}

This looks like an infinitely recursive function, but it is not because oss is an lvalue reference (yes, it is an lvalue reference because it has a name). 这看起来像一个无限递归函数,但它不是因为oss是左值引用(是的,它是左值引用,因为它有一个名称)。 So it will call the other overload. 所以它会调用另一个重载。

You still have to write two functions but one has a code that you don't have to maintain. 您仍然需要编写两个函数,但其​​中一个函数具有您不必维护的代码。

In summary, if "it makes sense"© to apply a function both to a (non const) lvalue reference and rvalue that also means that you can convert the rvalue into an lvalue and therefore you forward to a single function. 总之,如果“有意义”©将函数应用于(非常量)左值引用和右值,这也意味着您可以将右值转换为左值,因此转发到单个函数。 Note that the "it makes sense" depends in the context and the meaning of the intended code, and it is something that we have to "tell" the compiler by explictly calling the lvalue overload. 请注意,“它有意义”取决于上下文和预期代码的含义,并且我们必须通过明确地调用左值重载来“告诉”编译器。

I am not saying that this is better than using universal reference, I say it is an alternative and arguably the intention is more clear. 我并不是说这比使用普遍参考更好,我说它是另一种选择,可以说它的意图更清楚。

Editable code here: http://ideone.com/XSxsvY . 可编辑的代码: http//ideone.com/XSxsvY (Feedback is welcomed) (欢迎反馈)

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

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