Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test whether expression is a temporary?

With the following macro:

#define ASSERT_IF_TEMP(expr) static_assert(?, "Is temporary!");

What should I put for question mark?

like image 763
Clinton Avatar asked May 24 '11 08:05

Clinton


2 Answers

First we should clarify: What do you mean by "temporary"?

Many people mean different things when they say temporary. Technically, int() is not a temporary, but most people will include them into their own meaning of that term. Technically, given std::string s;, then move(s) isn't a temporary either, but you may want to treat it as one with your macro.

The first kind of "temporaries" I mentioned above are really "prvalue expressions". Those are the std::string("foo") or int() kind of things, but not the move(s) and also (for sure) not the s kind of things. The decltype operator yields a non-reference type for the first kind of "temporaries" I talked about above. For the second kind, move(s), which are xvalues, it will yield an rvalue reference. And for the "non-temporaries", i.e the s cases, it will yield an lvalue reference.

So to summarize, I will define three precise macros, and you can choose from them

#define IS_LVALUE(...) std::is_lvalue_reference<decltype((__VA_ARGS__))>::value
#define IS_XVALUE(...) std::is_rvalue_reference<decltype((__VA_ARGS__))>::value
#define IS_PRVALUE(...) !std::is_reference<decltype((__VA_ARGS__))>::value
like image 62
Johannes Schaub - litb Avatar answered Oct 14 '22 23:10

Johannes Schaub - litb


EDIT

I realized that my approach does exactly the same thing as the code you said did not work, only logically inverted:

std::is_lvalue_reference<decltype((expr))>::value

Could you elaborate as to exactly in what kind of a situation it works against your expectations?


You can exploit the reference-collapsing rules like this:

std::is_rvalue_reference<decltype((expr))&&>::value

If expr is an lvalue of some (possibly const) type T, decltype((expr)) will resolve to T&, and T& && will collapse back to T&.

Otherwise, if expr is an xvalue of some type T, decltype((expr)) will be T&&, and T&& && will reduce to just T&&.

Otherwise, expr will be a prvalue of some type T, decltype((expr)) will yield T, and thus the whole type will be T&&.

Examples:

template <typename T>
struct is_rvalue : std::is_rvalue_reference<T&&>
{};

struct x {};
x a; const x b{};

static_assert(is_rvalue<decltype((x()))>::value, "x() is an rvalue");
static_assert(!is_rvalue<decltype((a))>::value, "a is an lvalue");
static_assert(!is_rvalue<decltype((b))>::value, "b is an lvalue");
static_assert(is_rvalue<decltype((std::move(a))>::value, "std::move(a) is an rvalue");
like image 28
JohannesD Avatar answered Oct 14 '22 21:10

JohannesD