Why is this “min” template of cpp-next at fault?

前端 未结 5 698
时光取名叫无心
时光取名叫无心 2021-01-03 21:39

I was reading cpp-next where this min template is presented as an example of how verbose C++ code can be compared to python code

template 

        
5条回答
  •  囚心锁ツ
    2021-01-03 21:49

    Returning by reference might sometimes be a feature, not a bug. We'll return to this later. First a recap of the basics:

    int x; int y;
    x    // this is an lvalue
    y    // lvalue also
    x+y  // not an lvalue - you couldn't do (x+y) = 3
    x

    The last line shows that a ?: can often be an lvalue. i.e. You can do (x to set the smallest variable to 0 and leave the other one alone. Of course, you can't do (1<3?6:8)=0 as you can't do 6=0 or 8=0. So it's just an rvalue in that case.

    Inside min, x and y are the names of the function parameters and hence are lvalues. decltype(x is int&. (I found this other cpp-Next article useful also.)

    So why might this be a problem? Well, if the return type of min is a reference, then it will return a reference to one of x or y, the function parameters. The question now is, were x and y references themselves?

    Consider this use case:

    int m = 5; int n = 10;
    min(m,n) = 0; // do you want this to work?
    

    We have a decision to make. Maybe we want min to return references, if the arguments to min were references. I guess it's somewhat a matter of taste. If you rigorous want to return only non-references, this is easy to enforce with std::remove_reference around the decltype(x. But that's boring. Let's allow ourselves to (sometimes) return references; it might be more efficient and useful in many cases.

    If you use the original example definition of min, along with non-reference types for x or y, then min will return a reference to the local values among its parameters. This is bad as the references will be invalid and the behaviour undefined. For example, this would be bad:

    int p = min(5,8); // reading from a now-invalid reference.
    

    So, we have to go through a variety of use-cases and decide what behaviour we want:

    // Desired behaviour
    int m = 5;
    int n = 10;
    min(3,7); // return by value. i.e. return an int
    min(m,n); // return an int& which maps to either m or n
    min(3,n); // return by value
    min(foo(), bar()) // what makes sense here?
    

    Can we all agree on what behaviour we would want from such a min? And then, how do we implement it?

提交回复
热议问题