繁体   English   中英

c ++ 14中的泛型lambda:奇怪的行为

[英]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对象,该临时值是一个右值。

也就是说, ff("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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM