简体   繁体   English

lambda fct返回参考

[英]lambda fct returning reference

I have tried hard to make a lambda function return a value by reference without making a copy of the referenced value. 我已经尽力使lambda函数通过引用返回值而不复制引用的值。 My code example below illustrates the problem. 我下面的代码示例说明了问题。 It compiles and runs ok, but with the "//" commented line instead of the line above, it doesn't. 它编译并运行正常,但使用“//”注释行而不是上面的行,它不会。 I have found two workarounds (both illustrated in my example): 我找到了两个解决方法(在我的示例中都说明了):

  • wrap the result with std::ref() 用std :: ref()包装结果
  • return a pointer instead of a reference 返回指针而不是引用

But both workarounds are not what I really want, and I do not understand why they are necessary: The expression "makeRefA()" has already the type the lambda function returns (const A&) and thus must neither be copied nor converted. 但两种解决方法都不是我真正想要的,我不明白为什么它们是必要的:表达式“makeRefA()”已经是lambda函数返回的类型(const A&),因此既不能复制也不能转换。 By the way: The copy constructor is really called when I do not explicitly delete it (which in my "real" code is a performance problem). 顺便说一句:当我没有明确地删除它时(在我的“真实”代码中是性能问题), 真正调用了复制构造函数。 To me it looks like a compiler bug, but I have tried with several C++11-compilers which all show up the same error. 对我来说,它看起来像编译器错误,但我已经尝试了几个C ++ 11编译器,它们都显示相同的错误。 So is there something special concerning the "return" statement in a lambda function? 那么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;
}

output: 输出:

3
3

You can specify the return type 您可以指定返回类型

#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;
}

By default, the automatically-deduced type of a lambda is the non-reference version of a type 默认情况下,lambda的自动推导类型是类型的非引用版本

... the return type is the type of the returned expression (after lvalue-to-rvalue, array-to-pointer, or function-to-pointer implicit conversion); ...返回类型是返回表达式的类型(在左值到右值,数组到指针或函数到指针隐式转换之后); (source) (资源)

If you want a return type with a reference, you will have to specify it more explictly. 如果您想要一个带引用的返回类型,则必须更明确地指定它。 Here are some options: 以下是一些选项:

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

or simply be fully explicit about the return type with -> 或者只是完全明确返回类型->

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

If using C++14, then simply use decltype(auto) , 如果使用C ++ 14,那么只需使用decltype(auto)

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

The rules for decltype can be complicated at times. decltype的规则有时会很复杂。 But the fact that makeRefA() is an expression (as opposed to simply naming a variable) means that the type of the expression ( const A& ) is faithfully returned by decltype( makeRefA() ) . 但是makeRefA()是一个表达式(而不是简单地命名一个变量)这一事实意味着表达式的类型( const A& )被decltype( makeRefA() )忠实地返回。

According to http://en.cppreference.com/w/cpp/language/lambda , these rules apply to lambdas with no trailing return type: 根据http://en.cppreference.com/w/cpp/language/lambda ,这些规则适用于没有尾随返回类型的lambdas:

  • In C++11, lvalue-to-rvalue, array-to-pointer, or function-to-pointer implicit conversion are applied to the type of the returned expression. 在C ++ 11中,lvalue-to-rvalue,array-to-pointer或function-to-pointer隐式转换应用于返回表达式的类型。 (Here, the lvalue-to-rvalue conversion is what's hitting you.) (这里,左值到右值的转换就是你的命中。)
  • In C++14 and later, the type is deduced as for a function whose return type is declared auto ; 在C ++ 14及更高版本中,推导出类型为返回类型为auto的函数; and that in turn follows the rules for template argument deduction. 而这又遵循模板参数推导的规则。 Then, since auto includes no reference specification, that means that references and cv-qualifiers will be ignored. 然后,由于auto包含引用规范,这意味着将忽略引用和cv限定符。

The effect is probably desirable in most situations: for example, in this lambda expression 在大多数情况下,这种效果可能是合乎需要的:例如,在这个lambda表达式中

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

you probably intend to return an int , even though std::vector<int>::operator[] const returns const int& . 你可能打算返回一个int ,即使std::vector<int>::operator[] const返回const int&

As others have mentioned, you can override this behavior by giving an explicit trailing return type. 正如其他人所提到的,您可以通过提供显式的尾随返回类型来覆盖此行为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM