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

时间:2016-02-09 15:06:01

标签: c++ lambda c++14

也许有一些我没有完全得到的东西,但是在阅读"使用decltype on auto&&参数到std ::转发它们" (来自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&amp;&amp; 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&amp;),而f(&#34; fiorellino&#34;)和g(&#34; fiorellino&#34;)调用rvalues的大小重载。

我的问题是:为什么会这样?难道只有第二个lambda能够区分左值和右值吗? 我期待第一个lambda(f())调用两次大小(const std :: string&amp;),但显然这没有发生。

我做错了吗?

2 个答案:

答案 0 :(得分:3)

  

难道只有第二个lambda能够区分左值和左值吗?我期待第一个lambda(f())调用两次大小(const std :: string&amp;)

字符串文字"fiorellino"是一个左值,但是当它传递给size时,将从该字符串文字构造一个临时std::string对象,该临时值是一个右值。 / p>

x f f("fiorellino")的{​​{1}}类型为const char*。当const char*调用std:string时,f用于创建临时size(右值)。

这反过来会导致为f("fiorellino")基于此选择rvalue重载:&#34;当用作函数参数时,当函数的两个重载可用时,一个采用右值参考参数和另一个采用左值参考const参数,rvalue绑定到右值参考重载&#34; source)。

答案 1 :(得分:0)

行,

所以我想发表一个完整的答案(Michael,再次,谢谢)。 我感到困惑的是&#34; fiorellino&#34;是一个rvalue,并为它和这个临时对象创建一个临时对象,当一个const T&amp;和T&amp;&amp;可用它总是绑定到T&amp;&amp;版。到现在为止还挺好。这有意义(参见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&amp;过载。