2016-03-17 3 views
2

Рассмотрим:Generic лямбда, тип вычет фактического параметра (авто)

struct Foo { 
    std::vector<int> data() const { return vec; } 
    const std::vector<int>& c_data() const { return vec; } 

    std::vector<int> vec {}; 
}; 

auto lambda1 = [] (const std::vector<int>&) {}; 
auto lambda2 = [] (std::vector<int>&&) {}; 

auto lambda3 = [] (const auto&) {}; 
auto lambda4 = [] (auto&& p) {}; 

И использование является:

Foo f {}; 

lambda1 (f.data()); 
lambda1 (f.c_data()); 

lambda2 (f.data()); 
lambda2 (f.c_data()); // (X) 

lambda3 (f.data()); 
lambda3 (f.c_data()); 

lambda4 (f.data()); 
lambda4 (f.c_data()); // (Y) 

Этот код не компилировать из (X), что, конечно, понятном мной. Мы не можем привязывать константную ссылку, для ссылки rvalue. Хорошо.

Может ли кто-нибудь объяснить мне, что является фактическим типом параметра lambda4p? Здесь (Y) компилятор компилирует его, даже если я передаю ему аргумент const reference.

В чем разница между lambda2 и lambda4 типами в смысле типа вычета?

+1

'auto && p' является ссылкой для пересылки. Он может связываться с lvalues ​​и rvalues. – Michael

+1

См., Например, http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4164.pdf – Michael

ответ

4
auto lambda2 = [] (std::vector<int>&&) {}; 

Это примерно эквивалентно:

struct __lambda2 { 
    void operator()(std::vector<int>&&) {} 
} lambda2; 

Оператор вызова здесь принимает ссылку RValue - он принимает только rvalues. c_data() дает вам значение lvalue, следовательно, ошибку компилятора.

С другой стороны,

auto lambda4 = [] (auto&& p) {}; 

примерно эквивалентен:

struct __lambda4 { 
    template <class T> 
    void operator()(T&&) {} 
} lambda4; 

T&&, где T является параметром шаблона, не является ссылка Rvalue к выведенному типу (несмотря на то, что это как это выглядит) - это пересылка ссылка. Он может принимать как lvalues, так и rvalues ​​- и будет выводить T по-разному в зависимости от двух категорий значений (T=std::vector<int> при первом вызове и T=std::vector<int> const& во втором). Поскольку это принимает lvalues, ошибка компиляции отсутствует.

Обратите внимание, что ссылки на пересылку имеют форму T&& (для параметра шаблона T) и auto&&. Пример:

template <class U> 
struct X { 
    template <class T> void foo(T&&);  // forwarding reference 
    template <class T> void bar(T const&&); // rvalue reference to const T 
    void quux(U&&);      // rvalue reference to U 
}; 
Смежные вопросы