2013-06-15 2 views
4

В C++ незаконно преобразовывать значение rvalue в ссылку lvalue. Рассмотрим следующий код, где именующее ссылка привязана к RValue (лямбда):Ссылка rvalue и lvalue с лямбда-выражениями - gcc vs. msvc

int main() 
{ 
    auto& f = []() -> void {}; 
    return 0; 
} 

GCC (4.8.1) не принимает такой код (имеет смысл). Тем не менее, компилятор Microsoft принимает это, означая, что либо он принимает нестандартный код, либо C++ разрешает конкретный случай, когда ссылка lvalue привязана к lambda-выражению rvalue.

Вопрос: какое предположение верно?

ответ

6

Суть вашего вопроса: может rvalues ​​ быть связан с неконстантныхLvalue ссылки?

Стандарт говорит no. rvalues ​​ можно связать только с constlvalue ссылки.

Я считаю, соответствующий Стандартный параграф 8.5.3 /5:

Ссылка на тип «CV1 T1» инициализируется выражением типа «CV2 Т2» следующим образом:

...

  • в противном случае, ссылка должна быть именующей ссылкой на энергонезависимую Const станд e (т. е. cv1 будет const), или ссылка должна быть ссылкой на rvalue.

Однако Microsoft имеет давнюю «особенность», которая позволяет это нестандартной поведения, который объясняет, что вы свидетель.

+0

Да, это особенность. Иногда это полезно. У нас есть вопрос/ответ где-то, что объясняет это? –

+2

@MartinBa: В ответ на оба ваших комментария, что-либо вне стандарта, IMHO, не функция, а ошибка. C++ не идеален, но «усовершенствования» для конкретного поставщика - это PITA, когда дело доходит до функциональной совместимости, и их следует убивать огнем. YMMV (но когда вы начинаете работать над кросс-платформенными проектами, это становится очень важным). – syam

+1

@syam: Большое количество специфических для поставщика расширений. Никто не мог получить нигде без API-интерфейсов, специфичных для ОС. – Puppy

3

Однако компилятор Microsoft принимает это, означая, что либо он принимает нестандартный код, либо C++ разрешает конкретный случай, когда ссылка lvalue привязана к выражению лямбда rvalue.

MSVC известен тем, что имеет (не столь большое) расширение компилятора. Он просто позволяет связывание rvalues ​​с Lvalue ссылки непредставленных const:

A& x = A(); // Illegal in C++, allowed by MSVC 
+0

Эта функция имеет смысл для параметров функции: 'void f (A & a) {...}' можно вызывать с помощью '... f (A()); ... 'который * имеет * его варианты использования. –

+3

@MartinBa: Я действительно не увлекаюсь этим расширением. Прежде всего потому, что это серьезное изменение поведения по отношению к стандарту, а во-вторых, потому что оно кусает вас чаще, чем помогает. –

+0

@Martin Ba: Это делает мультиплатформенную разработку более сложной, если вы сначала разрабатываете MS, а затем тестируете на других платформах ... время от времени вы используете rvalue для ссылки на константу lvalue и MSVC не скажет вам. Так что это проявляется немного позже в GCC ... Всегда раздражает. По крайней мере, переключатель компилятора, чтобы отключить его в MSVC, было бы неплохо! – mmmmmmmm

2

Для quote Herb Sutter (председатель комитета по стандартизации в ISO C++):

Соответствующий компилятор C++ всегда может позволить иначе-нелегальную C++ код для компиляции и дать ему какое-то значение - эй, это может выбрать разрешите встроенный COBOL, если какой-нибудь компилятор-компилятор захотел реализовать это расширение, возможно, после нескольких слишкомких Tequilas. Для некоторых типов расширений стандарт C++ требует, чтобы компилятор, по крайней мере, испустил некоторую диагностику, чтобы сказать, что код недействителен ISO C++, как это делает этот компилятор.

Он объясняет далее, как в следующем примере, является незаконным:

// Example 2 

string f() { return "abc"; } 

void g() { 
string& s = f();  // illegal? 
    cout << s << endl; 
} 

Пожалуйста, посетите link по Sutter для объяснения, чтобы избежать дублирования статьи на SO.