不能使用显式类型的lambda

时间:2014-09-17 19:48:06

标签: c++ c++11 lambda

我有这段代码:

std::function<std::string&(std::string&)> change_str = [](std::string& str){
    return (str = "Hello world!");
};

std::string s;

std::cout << change_str(s) << std::endl;

它没有编译,并说:

main.cpp:8:47: error: no viable conversion from '(lambda at main.cpp:8:60)' to 'std::function<std::string &(std::string &)>'
    std::function<std::string&(std::string&)> change_str = [](std::string& str){
                                              ^            ~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/v1/functional:1448:5: note: candidate constructor not viable: no known conversion from '(lambda at main.cpp:8:60)' to 'nullptr_t' for 1st argument
    function(nullptr_t) _NOEXCEPT : __f_(0) {}
    ^
/usr/include/c++/v1/functional:1449:5: note: candidate constructor not viable: no known conversion from '(lambda at main.cpp:8:60)' to 'const std::__1::function<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > &(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > &)> &' for 1st argument
    function(const function&);
    ^
/usr/include/c++/v1/functional:1450:5: note: candidate constructor not viable: no known conversion from '(lambda at main.cpp:8:60)' to 'std::__1::function<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > &(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > &)> &&' for 1st argument
    function(function&&) _NOEXCEPT;
    ^
/usr/include/c++/v1/functional:1454:41: note: candidate template ignored: disabled by 'enable_if' [with _Fp = (lambda at main.cpp:8:60)]
                                        __callable<_Fp>::value &&
                                        ^
main.cpp:8:60: note: candidate function
    std::function<std::string&(std::string&)> change_str = [](std::string& str){
                                                           ^
1 error generated.

但是,如果我将std::function的声明更改为auto,那么它会起作用:

auto change_str = ...

为什么显式类型不适用于lambda?

4 个答案:

答案 0 :(得分:15)

没有返回类型的lambda是auto,并自动删除外部引用,因此您不会返回string&而只返回string

只需将功能声明为

即可
std::function<std::string&(std::string&)> change_str = 
[](std::string& str) -> string&  ///<--- NOTE THIS
{
    return (str = "Hello world!");
};

答案 1 :(得分:4)

您的lambda的推导返回类型为std::string,这就是您的声明不匹配的原因。但是当你明确指定返回类型时,它可以工作:

std::function<std::string&(std::string&)> change_str = 
        [](std::string& str) -> std::string& 
{
    return (str = "Hello world!");
};

答案 2 :(得分:3)

正如其他人所说,问题是默认的退货类型扣除推断std::string与预期的std::string&不兼容。

解决此问题的各种声明的目录:

// be completely explicit about the return type
[](std::string& str) -> std::string& {

 // be explicit about returning lvalue reference
[](std::string& str) -> auto& {

// be explicit that you're returning some kind of reference type,
// but use reference collapsing to determine if it's an lvalue or rvalue reference
[](std::string& str) -> auto&& { 

// use C++14 feature to deduce reference type
[](std::string& str) -> decltype(auto) {

这些按最少到最通用的顺序列出。但是在这种情况下,并不特别需要通用性:您只是推断返回类型,因为这是默认/最少打字。其中我可能会说明确可能是最好的:[](std::string &str) -> std::string& {

quantdev删除了他的答案,我认为这是另一个好建议:

[](std::string& str) {
    return std::ref(str = "Hello world!");
};

这是有效的,因为std::function只需要在参数和返回类型中具有适当的可转换性,并且返回std::ref的结果符合该要求。

使用std::ref和使用显式std::string &返回类型的内容对我来说都是可读的。对我的实现进行优化会对两者产生完全相同的效果,所以如果您更喜欢std::ref的外观,则没有理由不使用它。

答案 3 :(得分:2)

没有返回类型的lambda行为auto符合Template Argument Deduction规则,并且您的返回类型推断为std::string而不是std::string&

如果明确指定了类型,那么一切都很好

std::function<std::string&(std::string&)> change_str = 
                                 [](std::string& str) -> std::string& {
  return (str = "Hello world!");
};