2015-10-22 4 views
13

В this answer я использую этот код:захватывая Lambda статику в Вложенные лямбда

std::vector<std::vector<int>> imat(3, std::vector<int>(10)); 

std::for_each(imat.begin(), imat.end(), [&](auto& i) { 
    static auto row = 0; 
    auto column = 0; 
    std::transform(i.begin(), i.end(), i.begin(), 
     [&](const auto& /*j*/) { 
      return row * column++; 
    }); 

    ++row; 
}); 

Но я заметил некоторые проступок в захвате static auto row в зависимости от компилятора.

Clang 3.7.0 yields:

0 0 0 0 0 0 0 0 0 0
0 1 2 3 4 5 6 7 8 9
0 2 4 6 8 10 12 14 16 18

gcc 5.1.0 yields:

0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0

и Visual Studio 2015 дает мне компиляции ошибки времени:

An internal error has occurred in the compiler.

Если изменить захват вложенной захвата для захвата row я явно получаю ошибку компилятора:

identifier in capture must be a variable with automatic storage duration declared in the reaching scope of the lambda

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

EDIT:

Fozi pointed out что я может получить Visual Studio 2015 для компиляции и дают тот же результат, как Clang 3.7.0, если я изменить тип параметра вложенной Lambda от const auto& к const int&. Который кажется совершенно не связанным, но он работает.

Это не работает, если я попытаюсь зафиксировать row явно. В этом случае я все еще получаю ошибку компиляции:

identifier in capture must be a variable with automatic storage duration declared in the reaching scope of the lambda

Я сообщил в Visual Studio 2015 ошибка здесь: https://connect.microsoft.com/VisualStudio/feedback/details/1930409/capturing-a-lambdas-static-in-a-nested-lambda

+0

@ 865719 Хммм, я не могу найти решение, о котором вы говорите, но я обновлю свою Visual Studio 2015 и повторю попытку. –

+0

@ 865719 Моя Visual Studio 2015 обновлена ​​в соответствии с Windows Update. Кстати, я также могу реплицировать ошибку, вставив код в: http://webcompiler.cloudapp.net/ –

+1

Он компилируется, если вы меняете 'const auto &/* j * /' на 'const int &/* j */' – Fozi

ответ

3

Внутренний поставщик Compiler Error (ICE) всегда ошибка.

Нам не нужно фиксировать переменные статической продолжительности хранения, но нам необходимо захватить автоматические переменные odr-used. Из проекта C++ стандартный раздел 5.1.2:

The lambda-expression’s compound-statement yields the function-body (8.4) of the function call operator, but for purposes of name lookup (3.4), determining the type and value of this (9.3.2) and transforming idexpressions referring to non-static class members into class member access expressions using (*this) (9.3.1), the compound-statement is considered in the context of the lambda-expression.

так row должен быть виден во внутреннем лямбда и:

[...]If a lambda-expression or an instantiation of the function call operator template of a generic lambda odr-uses (3.2) this or a variable with automatic storage duration from its reaching scope, that entity shall be captured by the lambda-expression.[...]

Захват требуется только для this и переменных автоматической длительности хранения, если они odr- и мы можем видеть, что явный захват определяется только для автоматических переменных или это:

The identifier in a simple-capture is looked up using the usual rules for unqualified name lookup (3.4.1); each such lookup shall find an entity. An entity that is designated by a simple-capture is said to be explicitly captured, and shall be this or a variable with automatic storage duration declared in the reaching scope of the local lambda expression.

Для Visual Studio и gcc для соответствия результатам clang я могу перемещать row в глобальное пространство имен, see it live for gcc. Также, как Фози указывает на изменение const auto& /*j*/ до const int& /*j*/, он начинает работать.

Похоже, что gcc принимает явный захват неавтоматических переменных в качестве расширения и даже тогда явно фиксирует row, например [&, &row](const auto &) все еще производит все нули.

Далее для НКУ, если я перееду определение для row в main то я вижу следующее сообщение об ошибке (see it live):

/tmp/cchzwtQI.s: Assembler messages: 
/tmp/cchzwtQI.s:1572: Error: symbol `_ZL3row' is already defined 

который, кажется, как ошибки компилятора для меня.

Я не вижу никакой части стандарта, которая сделала бы неправильную форму оригинальной программы. Не следует также менять значение auto на int, и изменения, внесенные в polymorphic lambda proposal, также объясняют это различие.

+0

Вы видели [комментарий @Fozi made] (http://stackoverflow.com/questions/33285103/отлов-а-лямбда-статическая-в-вложенной лямбда/33289327 # comment54371126_33285103)? Этот код запускается и дает правильный результат в Visual Studio 2015: 'for_each (imat.begin(), imat.end(), [&] (auto & i) {static auto row = 0; auto column = 0; transform (i .begin(), i.end(), i.begin(), [&] (const int &/* j * /) {return row * column ++;}); ++ row;}); ' –

+0

Можете ли вы напомнить мне, что означает «переменные, которые используются odr»? Это одно правило определения? Разве не все переменные были бы тогда использованы? –

+1

@JonathanMee «odr-used» примерно эквивалентен «требует существования сущностей во время выполнения». – Columbo

 Смежные вопросы

  • Нет связанных вопросов^_^