Как проверить, является ли выражение временным? - PullRequest
6 голосов
/ 24 мая 2011

Со следующим макросом:

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

Что мне поставить для вопросительного знака?

Ответы [ 2 ]

9 голосов
/ 24 мая 2011

Сначала мы должны уточнить: что вы подразумеваете под «временным»?

Многие люди имеют в виду разные вещи, когда говорят, что они временные.Технически, int() не является временным, но большинство людей включит их в свое значение этого термина.Технически, если std::string s;, то move(s) также не является временным, но вы можете рассматривать его как единое целое с вашим макросом.

Первый вид «временных», которые я упомянул выше, на самом деле является «выражениями prvalue».Это вещи типа std::string("foo") или int(), но не move(s), а также (наверняка) не вещи s.Оператор decltype дает нереферентный тип для первого типа «временных значений», о которых я говорил выше.Для второго типа, move(s), которые являются значениями xvalue, он даст ссылку на rvalue.А для "невременных", то есть случаев s, он даст ссылку на lvalue.

Итак, подведя итог, я определю три точных макроса, и вы сможете выбрать из них

#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
5 голосов
/ 24 мая 2011

EDIT

Я понял, что мой подход делает то же самое, что код, который вы сказали, не работал, только логически инвертированный:

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

Не могли бы вы уточнить, в какой именно ситуации это работает против ваших ожиданий?

<Ч />

Вы можете использовать правила свертывания ссылок следующим образом:

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

Если expr является lvalue некоторого (возможно, константного) типа T, decltype((expr)) разрешится до T&, а T& && вернется к T&.

В противном случае, если expr является значением x некоторого типа T, decltype((expr)) будет T&&, а T&& && уменьшится до T&&.

В противном случае expr будет prvalue некоторого типа T, decltype((expr)) даст T, и, таким образом, весь тип будет T&&.

Примеры:

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");
...