Cha*_*eon 4 c++ forwarding-reference
当我想要使用函数参数复制语义const T&或使用函数参数移动语义时,如何处理通用引用T&&。后者隐藏了第一个。
下面是带有代数向量运算符的示例代码。
#include <array>
#include <iostream>
template<typename T>
void neg(T &a) { for (auto &i : a) i = -i; }
// object 'a' remains available
template<typename T>
auto operator-(const T &a) { std::cout << "1\r\n"; T b = a; neg(b); return b; }
// object 'a' terminates its life
template<typename T>
auto operator-(T &&a) { std::cout << "2\r\n"; neg(a); return std::move(a); }
// make an rvalue
template<typename T1, typename T2>
auto operator+(const T1 &a, const T2 &b) { return a; }
int main()
{
std::array<int, 4> a;
auto d = -(a+a); // outputs 2 : correct
auto e = -a; // outputs 2 : I want 1
auto f = -std::move(a); // outputs 2 : correct
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编辑:user17732522提出的解决方案之一(请为他投票)。
template<typename T>
auto operator-(T &&a)
{
std::cout << "2\r\n"; neg(a); return std::move(a);
}
template<typename T>
auto operator-(T &a)
{
std::cout << "1\r\n";
std::remove_cvref_t<T> b = a;
neg(b); return b;
}
int main()
{
std::array<int, 4> a;
auto d = -(a+a); // now outputs 2 : correct
auto e = -a; // now outputs 1 : correct
auto f = -std::move(a); // now outputs 2 : correct
const std::array<int, 4> b{1,2,3,4};
d = -(b+b); // now outputs 2 : correct
e = -b; // now outputs 1 : correct
return 0;
}
Run Code Online (Sandbox Code Playgroud)
另一个始终基于user17732522答案的解决方案是:
template<typename T>
requires(!std::is_reference_v<T>)
auto operator-(T &&a);
template<typename T>
auto operator-(const T &a);
Run Code Online (Sandbox Code Playgroud)
您只需const从 中删除const T&。
和using U = std::array<int, 4>;:
这里的问题是T&&推断T出U, not const U,因为ain mainisn't const。在重载解析中,绑定到U&而不是被认为更好。const U&
如果您const从 中删除const T&,那么推导后两个候选者都将具有函数参数U&,因此基于此,两者都不会更好。
然而,在函数模板的部分排序中,T&模板将获胜T&&,因此如果函数参数是左值,则将选择前者。
a然而,这确实会导致函数中的结果不被const限定。您可以const通过申请从中获取参考std::as_const。
或者,您可以使用requires子句或std::enable_if将T&&模板限制T为非引用类型。或者,您可以使用单个函数模板,并在其主体中决定如何根据 的引用类型进行操作if constexpr。相关类型特征:std::is_lvalue_reference_v<T>或std::is_reference_v<T>和std::is_lvalue_reference_v<decltype(a)>。