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?
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
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");
精彩评论