为什么当T = int&时构造函数Message(const T& data)和Message(T&& data)冲突?
Why constructor Message(const T& data) is conflict with Message(T&& data) when T = int&?
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);
}
有一个模板 class Message
有两个构造函数:Message(T&& data)
和 Message(const T& data)
,当我调用 makeMessage(a)
.
error: multiple overloads of 'Message' instantiate to the same signature 'void (const int &&)'
explicit Message(const T& data) : data(data) {
之前的声明在这里
explicit Message(T&& data) : data(std::move(data)) {
但是,当我调用 make_message(1024)
和 make_message(std::move(a))
时它起作用了。
那么当 T = int& 时,为什么构造函数 Message(const T& data)
与 Message(T&& data)
重复?
So why constructor Message(const T& data) is duplicate with Message(T&& data) when T = int&?
由于引用折叠规则。
没有引用引用之类的东西。当 T
是一个左值引用时——比方说 int &
,那么在句法上 T &
似乎是一个 int & &
。但是这种类型不存在。语言规则说在这种情况下 T &
会折叠成 int &
.
同样,也没有常量引用这样的东西(不要与常量引用混淆,人们在说常量引用时有时指的是常量引用)。当 T
是一个左值引用时——比方说 int&
,那么在句法上 T const
(与 const T
相同)似乎是一个 int& const
(不要与int const &
,等同于const int &
)。但是这种类型不存在。语言规则说在这种情况下 T const
会折叠成 int &
.
C++11 引入了右值引用,这给我们带来了新的折叠规则。简而言之,"rvalue reference to rvalue reference" 折叠成右值引用,但 "lvalue reference to any reference" 和 "any reference to lvalue reference" 折叠成左值引用。这条规则是转发引用工作原理的一部分。
因此,给定 T = int &
,它们声明相同的函数:
explicit Message(T&& data) // type of argument is int &
explicit Message(const T& data) // type of argument is int &
奖励:对于非引用也有折叠规则:没有 const const 类型这样的东西。因此,给定 const T
,其中 T
是 const int
,然后它会折叠成 const int
。 volatile
.
也是如此
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);
}
有一个模板 class Message
有两个构造函数:Message(T&& data)
和 Message(const T& data)
,当我调用 makeMessage(a)
.
error: multiple overloads of 'Message' instantiate to the same signature 'void (const int &&)'
explicit Message(const T& data) : data(data) {
之前的声明在这里
explicit Message(T&& data) : data(std::move(data)) {
但是,当我调用 make_message(1024)
和 make_message(std::move(a))
时它起作用了。
那么当 T = int& 时,为什么构造函数 Message(const T& data)
与 Message(T&& data)
重复?
So why constructor Message(const T& data) is duplicate with Message(T&& data) when T = int&?
由于引用折叠规则。
没有引用引用之类的东西。当 T
是一个左值引用时——比方说 int &
,那么在句法上 T &
似乎是一个 int & &
。但是这种类型不存在。语言规则说在这种情况下 T &
会折叠成 int &
.
同样,也没有常量引用这样的东西(不要与常量引用混淆,人们在说常量引用时有时指的是常量引用)。当 T
是一个左值引用时——比方说 int&
,那么在句法上 T const
(与 const T
相同)似乎是一个 int& const
(不要与int const &
,等同于const int &
)。但是这种类型不存在。语言规则说在这种情况下 T const
会折叠成 int &
.
C++11 引入了右值引用,这给我们带来了新的折叠规则。简而言之,"rvalue reference to rvalue reference" 折叠成右值引用,但 "lvalue reference to any reference" 和 "any reference to lvalue reference" 折叠成左值引用。这条规则是转发引用工作原理的一部分。
因此,给定 T = int &
,它们声明相同的函数:
explicit Message(T&& data) // type of argument is int &
explicit Message(const T& data) // type of argument is int &
奖励:对于非引用也有折叠规则:没有 const const 类型这样的东西。因此,给定 const T
,其中 T
是 const int
,然后它会折叠成 const int
。 volatile
.