使用非const字符串的C ++ lambda到std :: function错误

时间:2018-01-28 18:25:47

标签: c++ c++11 lambda

以下行给出了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。有什么解释吗?

3 个答案:

答案 0 :(得分:1)

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

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

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

允许 - 在foo的整个执行过程中,包含hello的字符串的生命周期是扩展

对于非const引用,没有这样的扩展规则,因此编译器不允许:

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

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

答案 1 :(得分:1)

从C ++ 11标准§20.8.11.2:

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

template<class F> function(F f);
     

要求:f对于参数类型ArgTypes应为 Callable   并返回类型R

在第一种情况下, Callable 表示

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

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

相反,rvalues可以绑定到 const lvalue references ,因此第二种情况可以。

答案 2 :(得分:0)

在你的第一个案例中,

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 

这里的错误是你试图获得一个非左值的左值引用,这违反了标准。

使用function<bool(string &, string &)>修复解决方案1(我想您可能尝试使用此版本):

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(); };

你试图得到一个对左值的恒定左值引用,这违反了标准。