2016-04-21 2 views
17

Я пытаюсь привести простой пример для операции, которая приводит к rvalue.Почему результат «decltype (i + j)» не является ссылкой на rvalue?

Этот тестовый пример должен был работать, но на удивление (для меня) результатом добавления двух int s является не rvalue (reference). Что мне здесь не хватает?

void test(int i, int j) 
{ 
    // this assert should pass, but fails: 
    static_assert(std::is_same<decltype(i + j), int&&>(), "i + j should be a rvalue"); 
    // this assert passed, but should fail: 
    static_assert(std::is_same<decltype(i + j), int>(), "this assert should fail..."); 
} 
+0

Это просто простые старые данные. Я не думаю, что вы можете std :: move a int .. – 0xbaadf00d

+0

Это всегда было int, с незапамятных времен (a.k.a. первые Unixes). Как бы вы переместили '2 + 2'? – bipll

+5

Вы можете очень много 'std :: move' a' int', и это в любом случае, кроме того, OP спрашивает о категории значений 'i + j'. –

ответ

33

i + j является prvalue expression,

prvalue ("чистый Rvalue") выражение является выражением, которое не имеет идентичность и могут быть перемещены с.

a + b, a% b, a & b, a < < b и все другие встроенные арифметические выражения;

не xvalue,

xvalue («истекающий значение») выражение является выражением, которое имеет идентичность и могут быть перемещены из.

И decltype specifier дает T для prvalue, не T&&.

а), если значение категория выражения xvalue, то decltype дает T & &;
b) если категория значений выражения равна lvalue, тогда decltype дает T &;
с), если значение категории выражения prvalue, то decltype дает Т.

Вы можете сделать это xvalue по std::move:

static_assert(std::is_same<decltype(std::move(i + j)), int&&>(), "std::move(i + j) is a xvalue then this static_assert won't fail"); 
+1

Абзац о 'decltype' - это то, что я пропустил в более общем случае. (Или, вообще говоря, разница между * значениями категорий * и тем, с чем они ссылаются *.) Спасибо! – anderas

+0

Я немного разъяснил вопрос, что знаю, что я ошибся. Разница в основном * - это rvalue * vs * связывается с ссылкой rvalue *. Я ожидал проверить второй, но сделал что-то еще. Вы хотите добавить это к своему ответу, или я должен написать свой собственный самопринятый ответ? (Так как это было бы решением моей реальной проблемы.) – anderas

+0

@anderas Я думаю, что хорошо написать свой ответ на основе вашего собственного аспекта и понимания. – songyuanyao

5

на основе @ songyuanyao-х Answer, я заметил, что моя ошибка проверял неправильную вещь: Мое намерение состояло в том, чтобы проверить, будет ли результат i+jсвязываться с ссылкой rvalue, но я проверил, is a rvalue reference.

decltype выводит тип, основанный на value category, не основаны на том, что reference type значение будет связываются с:

1), если значение категории выражения xvalue, то decltype урожаи T&&;
2) если категория значений выражения равна lvalue, тогда decltype дает T&;
3) если категория значений выражения равна prvalue, тогда decltype дает T.

Как показано в списке, поскольку C++ 11, rvalues не существует в качестве отдельной категории на самом низком уровне. Теперь они представляют собой составную категорию, содержащую как prvalues, так и xvalues. Вопрос, как написано, спрашивает, является ли выражение rvalue reference и проверяет, является ли оно xvalue.

Из вышеприведенного списка ясно, что i+j является prvalue, поэтому применяется третий случай. Это объясняет, почему decltype(i + j) является int, а не int&&. Оба xvalues и prvaluesсвязывать с ссылки rvalue.

Так, проверяя, связывается ли i+j к lvalue reference или rvalue reference подтверждает, что, действительно, связывается сrvalue reference:

void foo(const int& f) 
{ 
    std::cout << "binds to lvalue reference" << std::endl; 
} 

void foo(int&& f) 
{ 
    std::cout << "binds to rvalue reference" << std::endl; 
} 

void test(int i, int j) 
{ 
    foo(i); // lvalue -> lvalue ref 

    foo(std::move(i)); // xvalue -> rvalue ref 
    // (std::move converts the argument to a rvalue reference and returns it as an xvalue) 

    foo(i + j); // prvalue -> rvalue ref 
} 

В заключение:i+j является не ссылка Rvalue , но он привязывается к.

+0

Можете ли вы привести пример, который позволяет получить все три типа? – Chiel

+0

@Chiel, нет, и это то, что я пытался сделать с различием между * category * и *, что привязывает значение к *: существуют только ссылки rvalue и lvalue (а не 'xvalue', 'lvalue' и' prvalue' ссылки). 'prvalues' И' xvalues' связывают ссылки rvalue. – anderas

+0

@Chiel, если вы не хотите, чтобы я показывал, к каким значениям относятся эти категории. Я добавил это к образцу. – anderas