本文主要是介绍C++备忘录005:重载:引用、拷贝、移动和perfect forwarding,谁被调用了?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
重载函数的调用优先级问题非常?疼,但是正如Nicolai Josuttis所说:C++允许你把性能追求到极至,但这是有代价的。
(午夜梦回的时候,我经常问自己这代价是不是太过高昂了?)
看下面的简单例子
struct X {};void foo(const X &) {std::cout << "const X &\n";
}auto bar() {return X{};
}
foo
没有重载,只接受“传统“的参数类型const &
还有main
中几种调用情况的打印
int main() {const auto out = [width=20, &os=std::cout](const char * const tag){os << std::setw(width) << tag << ' ';};auto x = X{};const auto cx = X{};out("foo(x)");foo(x);out("foo(cx)");foo(cx);out("foo(X{})");foo(X{});out("foo(bar())");foo(bar());out("foo(std::move(x))");foo(std::move(x));
}
程序的输出是
foo(x) const X &foo(cx) const X &foo(X{}) const X &foo(bar()) const X &foo(std::move(x)) const X &
没什么值得吃惊的,我们然后再加一个重载
void foo(X &&) {std::cout << "X &&\n";
}
然后输出变成了,
foo(x) const X &foo(cx) const X &foo(X{}) X &&foo(bar()) X &&foo(std::move(x)) X &&
因为foo(x)
和foo(cx)
中,参数都是lvalue,所以匹配foo(const &)
,然后X{}
、bar()
和std::move(x)
都是rvalue,所以匹配foo(X &&)
我们再加一个perfect forwarding
template <typename T, typename = std::enable_if_t<std::is_constructible_v<X, T>>>
void foo(T &&) {std::cout << "T &&\n";
}
然后输出变成了
foo(x) T &&foo(cx) const X &foo(X{}) X &&foo(bar()) X &&foo(std::move(x)) X &&
foo(x)
的匹配从foo(const &)
变成了模版??!
这是因为foo(T&&)
这里能够匹配一切引用,x
是非const
类型,所以相比foo(const &)
来说,foo(T&&)
实例化的foo(&)
,对foo(x)
来说是更精确的匹配
我们可以进一步验证以下,增加一个重载
void foo(X &) {std::cout << "X &\n";
}
输出变成了
foo(x) X &foo(cx) const X &foo(X{}) X &&foo(bar()) X &&foo(std::move(x)) X &&
此时,foo(x)
优先匹配了foo(&)
,而不是模版
这篇关于C++备忘录005:重载:引用、拷贝、移动和perfect forwarding,谁被调用了?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!