通用lambda,实际参数的类型推导(auto)

时间:2016-03-17 16:16:41

标签: c++ c++14 type-deduction generic-lambda

考虑:

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),这段代码无法编译,这当然是我可以理解的。我们不能将const引用绑定到rvalue引用。细

有人可以解释一下lambda4 p参数的实际类型是什么吗?在这里(Y),编译器确实编译它,即使我将const引用参数传递给它。

类型演绎意义上的lambda2lambda4类型之间有什么区别?

1 个答案:

答案 0 :(得分:4)

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

这大致相当于:

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

此处的调用运算符采用右值引用 - 它只接受rvalues。 c_data()给你一个左值,因此编译错误。

另一方面,

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

大致相当于:

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

T&&,其中T是模板参数,不是对推导类型的右值引用(即使它看起来像这样) - 它是转发引用。它可以接受左值和右值 - 并且会根据两个值类别(第一个调用中的T和第二个中的T=std::vector<int>)以不同的方式推导T=std::vector<int> const&。由于这接受左值,因此没有编译错误。

请注意,转发引用的格式仅为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
};