带有非 const 字符串的 C++ lambda 到 std::function 错误

Posted

技术标签:

【中文标题】带有非 const 字符串的 C++ lambda 到 std::function 错误【英文标题】:C++ lambda to std::function error with non const strings 【发布时间】:2018-01-28 18:25:47 【问题描述】:

以下行在 c++ 11 中给出错误:

function<bool(string,string)> comp = [] (string& s1, string& s2) return s1.length() > s2.length(); ;

但事实并非如此:

function<bool(string,string)> comp = [] (const string& s1, const string& s2) return s1.length() > s2.length(); ;

第二次调用的参数为 const。有什么解释吗?

【问题讨论】:

临时对象或文字不能绑定到对非常量对象的引用。 Any good beginners book 应该告诉你的。 右值(比如传值的参数)不能绑定到非const左值引用,但是可以绑定到const左值引用。 你知道自动对 lambda 有效吗? auto comp = ... 【参考方案1】:

它与 lambdas 没有任何关系。当您将函数声明为采用 const 引用 时,您将激活 lifetime extension。

void foo(const std::string& ref) . . . 
void bar(std::string& ref) . . . 

foo(std::string("hello")); 

允许 - 包含 hello 的字符串的生命周期在foo 的整个执行过程中延长

对于非常量引用,没有这样的扩展规则,所以编译器不会允许:

bar(std::string("farewell")); 

因为如果确实如此,在foo 开始时,它只会引用曾经是告别字符串的被破坏的残余物。

【讨论】:

【参考方案2】:

来自 C++11 标准第 20.8.11.2 节:

template<class R, class... ArgTypes>
class function<R(ArgTypes...)>  /* ... */ ;

template<class F> function(F f);

要求:f 对于参数类型 ArgTypes 应该是可调用 并返回类型R

在您的第一种情况下,Callable 意味着

INVOKE(f, declval<string>(), declval<string>(), bool)

格式正确,其中f 是 lambda,declval 表示 string 类型的右值对象。由于右值不能绑定到非常量左值引用,所以这里不满足这个条件。

相反,右值可以绑定到const左值引用,所以第二种情况是可以的。

【讨论】:

【参考方案3】:

在您的第一种情况下,

function<bool(string,string)> comp = [] (string& s1, string& s2) return s1.length() > s2.length(); ;

你正在尝试编译这样的东西:

bool comp(string& s1, string& s2)/*...*/
comp(string(), string());//passing a lvalue reference to a rvalue 

这里的错误是您试图获取对右值的非常量左值引用,这违反了标准。

修复解决方案1,使用function&lt;bool(string &amp;, string &amp;)&gt;(我想你可能正在尝试使用这个版本):

function<bool(string&,string&)> comp = [] (string& s1, string& s2) return s1.length() > s2.length(); ;

解决方案 2,使用右值引用:

function<bool(string,string)> comp = [] (string&& s1, string&& s2) return s1.length() > s2.length(); ;

在第二种情况下,

function<bool(string,string)> comp = [] (const string& s1, const string& s2) return s1.length() > s2.length(); ;

您正试图获取对右值的 const 左值引用,这不违反任何标准。

【讨论】:

以上是关于带有非 const 字符串的 C++ lambda 到 std::function 错误的主要内容,如果未能解决你的问题,请参考以下文章

lambda(参数)中的 const 限定符,用于带有 std::sregex_token_iterator 的 std::transform

C++ const总结

在 C++ 中将非 const 转换为 const

C++ 非 const 右值参数解决方法

VS2010 中的 C++ 嵌套 lambda 错误,带有 lambda 参数捕获?

当容器在 C++ 中为 const 时,如何对容器持有的对象进行非 const 访问