#c #c 11 #static-assert
#c #c 11 #статическое утверждение
Вопрос:
С помощью следующего макроса:
#define ASSERT_IF_TEMP(expr) static_assert(?, "Is temporary!");
Что я должен поставить вместо вопросительного знака?
Комментарии:
1. Результат выражения всегда является временным.
2. @Clinton: Можете ли вы пояснить, почему вы хотите это сделать?
3. @Neil: Ерунда. Если у меня есть
char* ptr = some_pointer();
, то выражение*ptr
является значением lvalue.4. @Neil Butterworth За некоторое определение временного. С практической точки зрения, временное соответствует тому, что стандарт называет rvalue , а результатом некоторых выражений являются lvalues .
5. вы могли бы утверждать, что что-то является временным, если находится в стеке (особенно смещение), а не в куче?
Ответ №1:
Сначала мы должны уточнить: что вы подразумеваете под «временным»?
Многие люди имеют в виду разные вещи, когда говорят «временный». Технически, int()
не является временным, но большинство людей включают их в свое собственное значение этого термина. Технически, данное значение std::string s;
, then move(s)
также не является временным, но вы можете захотеть рассматривать его как единое целое с вашим макрокомандой.
Первый вид «временных», о которых я упоминал выше, на самом деле являются «выражениями prvalue». Это вещи типа std::string("foo")
или int()
, но не move(s)
а также (наверняка) не s
такие вещи. decltype
Оператор выдает не ссылочный тип для первого вида «временных элементов», о которых я говорил выше. Для второго вида, move(s)
которые являются значениями x, это приведет к ссылке на значение rvalue. И для «временных», т.е. s
случаев, это приведет к ссылке на значение.
Итак, подводя итог, я определю три точных макроса, и вы сможете выбирать из них
#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
Комментарии:
1. Спасибо за очень подробный ответ. На самом деле я ищу prvalues , поскольку у этого могут быть удалены копии, если обернуть их в лямбда-выражения (следовательно, отложить их оценку) перед передачей их функциям. Делать это для других вещей, я считаю, пустая трата времени.
2. Есть ли способ определить разницу между std::move(x) и std::move(X())? (последнее выигрывает от отложенной оценки).
Ответ №2:
Редактировать
Я понял, что мой подход делает точно то же самое, что и код, который, как вы сказали, не работал, только логически инвертированный:
std::is_lvalue_reference<decltype((expr))>::value
Не могли бы вы уточнить, в какой именно ситуации это работает вопреки вашим ожиданиям?
Вы можете использовать правила свертывания ссылок следующим образом:
std::is_rvalue_reference<decltype((expr))amp;amp;>::value
Если expr
является значением lvalue некоторого (возможно, const) типа T
, decltype((expr))
будет преобразовано в Tamp;
и Tamp; amp;amp;
свернется обратно в Tamp;
.
В противном случае, если expr
это xvalue некоторого типа T
, decltype((expr))
будет Tamp;amp;
, и Tamp;amp; amp;amp;
уменьшится до просто Tamp;amp;
.
В противном случае, expr
будет prvalue некоторого типа T
, decltype((expr))
выдаст T
, и, таким образом, весь тип будет Tamp;amp;
.
Примеры:
template <typename T>
struct is_rvalue : std::is_rvalue_reference<Tamp;amp;>
{};
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");