带有非 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<bool(string &, string &)>
(我想你可能正在尝试使用这个版本):
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