Параметр возвращаемого генерического лямбда предположительно теней параметра свободной функции

Компиляция следующего кода

template <typename X, typename F>
auto apply(X x, F f)
{
    return f(x);
}

template <typename Y>
auto add_value(Y y)
{
    return [y](auto x)
    {
        return x + y;
    };
}

int main()
{
    apply(1, add_value(2));
}

с g++ (например, v. 5.4) дает теневые предупреждения.

$ g++ -Wshadow -Werror -std=c++14 shadow_test.cpp 
shadow_test.cpp: In instantiation of ‘add_value(Y)::<lambda(auto:1)> [with auto:1 = int; Y = int]’:
shadow_test.cpp:4:13:   required from ‘auto apply(X, F) [with X = int; F = add_value(Y) [with Y = int]::<lambda(auto:1)>]’
shadow_test.cpp:18:26:   required from here
shadow_test.cpp:10:22: error: declaration of ‘int x’ shadows a parameter [-Werror=shadow]
     return [y](auto x)
                      ^
shadow_test.cpp:2:14: note: shadowed declaration is here
 auto apply(X x, F f)
              ^
cc1plus: all warnings being treated as errors

Я не понимаю, почему. Может кто-нибудь объяснить?

Ответ 1

Должна быть ошибка.

  • Переменная не затеняется, поскольку она не находится в охватывающей области лямбда, однако создает правильный результат.
  • VS2015 не вызывает никаких предупреждений.
  • Clang не создает никаких предупреждений.

Это спекулятивно, но, вероятно, происходит следующая подстановка (или что-то вроде этого):

#include <iostream>

template <typename X, typename Y>
auto add_value(X x, Y y)
{
    auto f = [y](auto x)
    {
        return x + y;
    };
    return f(x);
}

int main()
{
    std::cout << add_value(1, 2);
}

Эта программа создает предупреждающее предупреждение о Clang, но даже тогда оно дает правильный результат. VS2015 по-прежнему не считает это достойным предупреждения, но, вероятно, это неправильно, потому что имена из охватывающей области лямбда также находятся в области лямбда. Если они не будут захвачены, они могут быть использованы, но не могут использоваться odr, как описано здесь.