为什么构造函数 Message(const T&data) 与 Message(T&& data) 冲突,当 T = int&时?

Why constructor Message(const T& data) is conflict with Message(T&& data) when T = int&?

本文关键字:data Message int 冲突 构造函数 为什么 const      更新时间:2023-10-16
template <typename T>
struct Message {
T data;
explicit Message(T&& data) : data(std::move(data)) {
std::cout << "Move data" << std::endl;
}
explicit Message(const T& data) : data(data) {
std::cout << "Copy data" << std::endl;
}
};
template <typename T>
inline Message<T>*
makeMessage(T&& data) {
return new Message<T>{std::forward<T>(data)};
}

int main() {
const int a = 1024;
auto *copy_msg = makeMessage(a);
}

有一个模板类Message有两个构造函数:Message(T&& data)Message(const T& data),调用makeMessage(a)时出现以下编译时错误。

错误:"消息"的多个重载实例化为同一签名"void (const int &&(">

显式消息(const T& data( : data(data( {

以前的声明在这里

显式消息(T&& data( : data(std::move(data(( {

但是,当我打电话给make_message(1024)make_message(std::move(a))时,它可以工作。

那么为什么构造函数Message(const T& data)在 T = int&时与Message(T&& data)重复呢?

那么,当 T = int&时,为什么构造函数 Message(const T& data( 与 Message(T&& data( 重复呢?

因为引用折叠规则。

没有参考这样的东西。当T是一个左值引用时 - 假设int &,那么语法上T &似乎是一个int & &。但是这种类型不存在。语言规则说,在这种情况下,T &崩溃成int &.

同样,没有常量引用这样的东西(不要与引用 const 混淆,人们有时在说 const 引用时指的是 const(。当T是左值引用时 - 假设int&,那么语法上T const(与const T相同(似乎是一个int& const(不要与int const &混淆,这与const int &相同(。但是这种类型不存在。语言规则说,在这种情况下,T const崩溃成int &.

C++11引入了右值引用,这为我们带来了新的折叠规则。简而言之,"对右值引用的右值引用"折叠为右值引用,但"对任何引用的左值引用"以及"对左值引用的任何引用"折叠为右值引用。此规则是转发引用工作原理背后的魔力的一部分。

因此,给定T = int &,它们声明相同的函数:

explicit Message(T&& data)      // type of argument is int &
explicit Message(const T& data) // type of argument is int &

奖励:对于非引用,还有折叠规则:没有常量常量类型这样的东西。因此,给定const TT在哪里const int,那么它就会崩溃成const intvolatile也是如此。