也许有一些我没有完全得到的东西,但是在阅读"使用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;),但显然这没有发生。
我做错了吗?
答案 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;过载。