Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it well-defined to cast xvalues to lvalues for passing to functions?

Recently I've discovered that sometimes being able to turn rvalues temporarily into lvalues can be useful for me.

I've been using the following tool:

#include <type_traits>

template <typename T>
inline constexpr std::remove_reference_t<T> &lvalue(T &&r) noexcept {
    return static_cast<std::remove_reference_t<T> &>(r);
}

It's useful when you have to use functions that require lvalues as arguments, but you don't have any interest in what those particular values get changed into. For when you are interested in other output vectors that are not related to the given specific argument.

For example, this:

std::string get_my_file() {
    std::ifstream ifs("myfile.txt");
    return {std::istreambuf_iterator<char>(ifs), {}};
}

can be changed to this:

std::string get_my_file() {
    return {std::istreambuf_iterator<char>(lvalue(std::ifstream("myfile.txt"))),
            {}};
}

And this:

std::string temp1 = get_my_shader();
const char *temp2 = temp1.c_str();
glShaderSource(a, 1, &temp2, nullptr);

can be changed to this:

glShaderSource(a, 1, &lvalue(get_my_shader().c_str()), nullptr);

And allow things like this:

void foo(int *x) {
    std::cout << *x << std::endl;
}

foo(&lvalue(5));

I'd like to be sure whether I'm invoking undefined-behavior or not in any of this, because I don't see any, although there may be some casting rule that would turn it illegal (which I ignore). Regarding lifetime of temporaries, I don't see a problem since, AFAIK, rvalues live until the end of full-expression and usage of the function is restricted to that.

There's a recent change to the standard about reinterpret_cast and xvalues that seems to be on topic:

https://stackoverflow.com/a/26793404/1000282

EDIT:

Better version using reference collapsing as suggested:

template <typename T>
constexpr T &lvalue(T &&r) noexcept { return r; }
like image 418
pepper_chico Avatar asked Nov 21 '14 02:11

pepper_chico


People also ask

What do you call the value values that are passed into a function?

The values that are passed in the function call are called the actual parameters. The values received by the function (when it is called ) are called the formal parameters.

Are the values passed into the function?

Arguments are Passed by Value The parameters, in a function call, are the function's arguments. JavaScript arguments are passed by value: The function only gets to know the values, not the argument's locations. If a function changes an argument's value, it does not change the parameter's original value.

What does it mean to pass in a function?

Passing Functions as Arguments. Functions are data, and therefore can be passed around just like other values. This means a function can be passed to another function as an argument. This allows the function being called to use the function argument to carry out its action.

How do you pass data into a function?

When there are multiple functions (which is most of the time), there needs to be a way to pass data between the functions. This is done by passing values in parenthesis: myFunction(myData). Even when there is no data to be passed, we still have to declare and execute functions by using parenthesis: myFunction().


1 Answers

As you said, you took care to not let any pointer or reference to the temporaries escape their scope.
Using your lvalue-function (mine is called no_move) makes it easier to break that stricture inadvertently.

Next, let's look at what xvalues are: Expiring objects, but objects nevertheless.
This means, you can ignore they are on their funeral tour (if you pass them to a function, that function will naturally do so, unless you ask to take advantage).

The last point you mentioned was calling with a prvalue, which is most certainly not an object.
But even that is not a problem, as on calling the function, a temporary will be created.
And that temporary will naturally also survive to the end of the statement.

As an aside, using std::remove_reference_t<T>& is unneccessary for the return-type of lvalue, you can use T& directly and rely on the reference-collapsing-rules. Also, the static_cast and inline are superfluous.

template <typename T> constexpr T& lvalue(T&& r) noexcept {return r;}
like image 106
Deduplicator Avatar answered Sep 28 '22 11:09

Deduplicator