lambda fct返回引用

时间:2016-05-22 14:05:45

标签: c++ c++11 lambda

我努力使lambda函数通过引用返回一个值而不用制作引用值的副本。 我下面的代码示例说明了问题。它编译并运行正常,但使用“//”注释行而不是上面的行,它不会。 我找到了两个解决方法(在我的示例中都有说明):

  • 用std :: ref()
  • 包装结果
  • 返回指针而不是引用

但两种解决方法都不是我真正想要的,我不明白为什么它们是必要的:表达式“makeRefA()”已经是lambda函数返回的类型(const A&),因此既不能复制也不能复制转换。顺便说一下:当我没有明确地删除它时,复制构造函数真正被调用(在我的“真实”代码中是性能问题)。 对我来说,它看起来像编译器错误,但我已经尝试了几个C ++ 11编译器,它们都显示相同的错误。那么lambda函数中的“return”语句有什么特别之处吗?

#include <functional>
#include <iostream>

struct A {
  A(int i) : m(i) { }
  A(const A&) = delete;
  int m;
};

void foo(const A & a) {
  std::cout << a.m <<'\n';
}

const A & makeRefA() {
  static A a(3);
  return a;
}

int main() {
  std::function<const A&()> fctRef = [&]
    { return std::ref(makeRefA()); }; //compiles ok
    //{ return makeRefA(); }; //error: use of deleted function 'A::A(const A&)'
  foo(fctRef());

  std::function<const A*()> fctPtr = 
    [&] { return &makeRefA(); };
  foo(*fctPtr());

  return 0;
}

输出:

3
3

3 个答案:

答案 0 :(得分:7)

您可以指定返回类型

#include <functional>
#include <iostream>

struct A {
    A(int i) : m(i) { }
    A(const A&) = delete;
    int m;
};

void foo(const A & a) {
    std::cout << a.m <<'\n';
}

const A & makeRefA() {
    static A a(3);
    return a;
}

int main() {
    std::function<const A&()> fctRef = [&]()->const A&
//    { return std::ref(makeRefA()); }; //compiles ok
    { return makeRefA(); }; // works
    foo(fctRef());

    std::function<const A*()> fctPtr =
    [&] { return &makeRefA(); };
    foo(*fctPtr());

    return 0;
}

答案 1 :(得分:7)

默认情况下,lambda的自动推导类型是类型

的非引用版本
  

...返回类型是返回表达式的类型(在左值到右值,数组到指针或函数到指针隐式转换之后); (source)

如果您想要一个带引用的返回类型,则必须更明确地指定它。以下是一些选项:

[&]()
-> decltype( makeRefA() )
{ return makeRefA()); };

或仅仅使用->

完全明确返回类型
[&]()
-> const A&
{ return makeRefA(); }

如果使用C ++ 14,则只需使用decltype(auto)

[&]()
-> decltype(auto)
{ return makeRefA(); }

decltype的规则有时会很复杂。但是makeRefA()是一个表达式(而不是简单地命名变量)这一事实意味着表达式(const A&)的类型由decltype( makeRefA() )忠实地返回。

答案 2 :(得分:2)

根据http://en.cppreference.com/w/cpp/language/lambda,这些规则适用于没有尾随返回类型的lambdas:

  • 在C ++ 11中,lvalue-to-rvalue,array-to-pointer或function-to-pointer隐式转换应用于返回表达式的类型。 (这里,左值到右值的转换就是你的命中。)
  • 在C ++ 14及更高版本中,推导出类型为返回类型为auto的函数;而这又遵循模板参数推导的规则。然后,由于auto不包含引用规范,这意味着将忽略引用和cv限定符。

在大多数情况下,效果可能是理想的:例如,在这个lambda表达式中

[](const std::vector<int>& v) { return v[0]; }

您可能打算返回int,即使std::vector<int>::operator[] const返回const int&

正如其他人所提到的,您可以通过提供显式的尾随返回类型来覆盖此行为。