[英]Generic lambdas in c++14: weird behavior
也许有一些我没有完全得到的东西,但是在阅读“使用decltype on auto && parameters to std :: forward them”(来自Effective Modern C ++)后,我发现了一些非常奇怪的东西。
我们假设有
int size(std::string &&s) { std::cout <<"std::string&&" <<std::endl; return s.size(); }
int size(const std::string &s) { std::cout <<"std::string const &" <<std::endl; return s.size(); }
我定义了两个lambas(一个用auto,一个用于正确转发auto && param):
auto f = [](auto x) { return size(x); };
std::string s{ "buonanotte" };
std::cout <<f(s) <<std::endl;
std::cout <<f("fiorellino") <<std::endl;
auto g = [](auto&& x) { return size(std::forward<decltype(x)>(x)); };
std::cout <<g(s) <<std::endl;
std::cout <<g("fiorellino") <<std::endl;
好吧,结果是相同的:f(s)和g(s)调用大小(const std :: string&),而f(“fiorellino”)和g(“fiorellino”)调用rvalues的大小重载。
我的问题是:为什么会发生这种情况? 不仅第二个lambda能够区分左值和右值吗? 我期待第一个lambda(f())调用两次大小(const std :: string&),但显然这没有发生。
难道我做错了什么?
不仅第二个lambda能够区分左值和右值吗? 我期待第一个lambda(f())调用两次大小(const std :: string&)
字符串文字"fiorellino"
是一个左值,但是当它传递给size
,将从该字符串文字构造一个临时的std::string
对象,该临时值是一个右值。
也就是说, f
中f("fiorellino")
的x
类型将是const char*
。 当f
调用size
时, const char*
用于创建临时std:string
(rvalue)。
这反过来导致为f("fiorellino")
选择rvalue过载,基于此: “当用作函数参数并且当函数的两个重载可用时,一个采用rvalue引用参数,另一个采用左值引用const参数,rvalue绑定到右值引用过载“ ( 源 )。
好,
所以我想发表一个完整的答案(Michael,再次,谢谢)。 令我感到困惑的是,“fiorellino”是一个右值,为它和这个临时对象创建了一个临时对象,当const T&和T &&可用时,它将始终绑定到T &&版本。 到现在为止还挺好。 这实际上是有意义的(参见http://en.cppreference.com/w/cpp/language/value_category ,其中描述了rvalues)。
我现在用这种方式改变了我的例子:
int size(std::string &&s) { std::cout <<"std::string&&" <<std::endl; return s.size(); }
int size(const std::string &s) { std::cout <<"std::string const &" <<std::endl; return s.size(); }
std::string generate(int x) { return std::to_string(x); }
auto f = [](auto x) { return size(x); };
std::string s{ "buonanotte" };
std::cout <<"f(): "; f(s);
std::cout <<"f(): "; f("fiorellino");
std::cout <<"f(): "; f(generate(123));
std::cout <<"f(): "; f(std::move(s));
auto g = [](auto&& x) { return size(std::forward<decltype(x)>(x)); };
std::string s2{ "buonanotte" };
std::cout <<"g(): "; g(s2);
std::cout <<"g(): "; g("fiorellino");
std::cout <<"g(): "; g(generate(123));
std::cout <<"g(): "; g(std::move(s2));
现在,generate(123)创建了一个正确的临时,它将被第一个lambda错误地转发,但是被第二个lambda正确转发。
看看输出:
f(): std::string const &
f(): std::string&&
f(): std::string const &
f(): std::string const &
g(): std::string const &
g(): std::string&&
g(): std::string&&
g(): std::string&&
即使我使用std :: move(s)(创建一个rvalue-reference),第一个lambda总是选择const T&overload。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.