2012-01-13 2 views
6

У меня есть три вызова функций, которые, как я думаю, следует рассматривать (примерно) одинаково, но ясно, что это не так. Я пытаюсь понять, почему один из трех не компилирует (g ++ -std = C++ 0x).rvalue binding confusion в C++

// Minimal example to reproduce a compile bug I want to understand. 

#include <iostream> 
#include <string> 

using namespace std; 


void bar(const string &&x) { cout << "bar: " << x << endl; } 

string returns_a_string() { return string("cow"); } 

int main(int argc, char *argv[]) 
{ 
    bar(string("horse"));  // ok 
    bar(returns_a_string()); // ok 
    string aardvark = "aardvark"; 
    bar(aardvark);   // not ok, fails to compile, error in next comment 
    /* 
     rvalue-min.cpp:29:22: error: cannot bind ‘std::string {aka std::basic_string<char>}’ lvalue to ‘const string&& {aka const std::basic_string<char>&&}’ 
     rvalue-min.cpp:10:6: error: initializing argument 1 of ‘void barR(const string&&)’ 
    */ 
} 

Этот вопрос немного по линии C++0x rvalue references - lvalues-rvalue binding, , но, если он ответил там, мои извинения, я не смог отогнать его.

Я хочу, чтобы иметь возможность вызывать мою функциональную панель() с любой строкой, и она просто работает. Достаточно определить void barR(const string &x), но я бы очень хотел понять, почему.

Большое спасибо за помощь в понимании того, почему третий звонок отличается.

+3

Обратите внимание, что вы не можете делать ничего полезного с помощью ссылки * константы * rvalue. Обычно вы хотите объявить 'bar (std :: string &&)'. –

+0

@KerrekSB - хорошая точка – jma

ответ

14

Цель ссылочных параметров r-значения заключается в том, чтобы обнаруживать, когда объект является r-значением. Потому что, если объект является r-значением, функция знает, что он не будет использоваться снова, поэтому он может делать с ним все, что захочет. Если l-значение может связываться с ссылкой на r-значение, это будет означать, что обнаружение, о котором я говорил, на самом деле не имело места.

Если вы хотите передать l-значение одной из этих функций, вам необходимо использовать std::move. Передача объекта через std::move функции, которая принимает ссылку на r-значение, похожа на высказывание: «вот, возьмите этот объект, разорвите его кишки, мне все равно, что с ним происходит».

Для ваших целей правильным ответом является указание параметра const. Значение r отлично согласуется с ссылкой на const. За исключением конструкторов перемещения, создание опорных параметров r-значения почти никогда не является правильным.

+0

Разве этот ответ не согласен с примером в этой статье (Чтобы найти конкретно: Ctrl + F "// Line 31"): http://blogs.msdn.com/b/vcblog/archive/2009/02/03 /rvalue-references-c-0x-features-in-vc10-part-2.aspx –

+0

@sftrabbit: Да, но это согласуется с языковым стандартом (а также с GCC, который отвергает код в этой статье). –

+0

Спасибо. Раньше я заметил эту ошибку в статье, но так и не смог ее проверить. –

4

Вам необходимо использовать std::move. Это отлично работает:

bar(std::move(aardvark)); 
+0

Достаточно справедливо, хотя это налагает работу на клиента. Полезно знать, хотя, спасибо. – jma

+1

@jma: клиент должен сделать это, потому что клиент дает прямое разрешение на функцию, чтобы вырвать кишки из объекта. (поэтому const является нечетным.) Вы должны иметь только (const std :: string & rhs) код, чтобы взять все. –