Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++11 为什么在重载解析中右值引用参数与常量引用匹配?_C++11_Constants_C++14_Rvalue Reference_C++17 - Fatal编程技术网

C++11 为什么在重载解析中右值引用参数与常量引用匹配?

C++11 为什么在重载解析中右值引用参数与常量引用匹配?,c++11,constants,c++14,rvalue-reference,c++17,C++11,Constants,C++14,Rvalue Reference,C++17,可能相关的文章: 对于STL容器C,std::begin(C)和类似的访问函数,包括std::data(C)(从C++17开始)应该具有与C::begin()和其他相应的C方法相同的行为。然而,由于涉及左值/右值引用和常量的重载解析的细节,我观察到一些有趣的行为 DataType1是int*很容易预料到的。此外,通过Boost的类型\u id\u和\u cvr确认const向量给出了int const*这并不奇怪 using T = vector<int>; using Da

可能相关的文章:

对于STL容器
C
std::begin(C)
和类似的访问函数,包括
std::data(C)
(从C++17开始)应该具有与
C::begin()
和其他相应的
C
方法相同的行为。然而,由于涉及左值/右值引用和常量的重载解析的细节,我观察到一些有趣的行为

DataType1
int*
很容易预料到的。此外,通过Boost的
类型\u id\u和\u cvr
确认
const向量
给出了
int const*
这并不奇怪

using T = vector<int>;
using DataType1 = decltype(T().data()); // int*
using CT = const T;
using DataType2 = decltype(CT().data()); // int const*

using boost::typeindex::type_id_with_cvr;
cout << type_id_with_cvr<DataType1>() << endl; // prints int*
...
问题:造成这种差异的原因是什么?我希望
C.data()
std::data(C)
的行为方式相同


我的一些研究:为了获得
DataType3
int*
T
必须显式转换为非常量左值引用类型。我试过了12月的,结果成功了

using DataType3 = decltype(std::data(std::declval<T&>())); // int*
在解析
std::data
的重载函数时,
T()
是非常量值引用,它与
const T&
版本匹配,而不是与
T&
版本匹配


在标准中很难找到这个特定的重载解析规则(13.3,over.match)。如果有人能指出这个问题的确切规则,那就更清楚了。

这种行为归因于过载解决规则。根据标准8.5.3/p5.2引用[dcl.init.ref],右值引用绑定到常量左值引用。在本例中:

std::data(T())
您向
std::data
提供一个右值。因此,由于过载解析规则,过载:

template <class _Cont> constexpr
auto data(const _Cont& __c) -> decltype(__c.data()) { return __c.data(); }
template constexpr
自动数据(const_Cont&__c)->decltype(__c.data()){return__c.data();}
这是一场更好的比赛。因此,您会得到
const int*


您无法将临时值绑定到非常量左值引用。

唯一稍微令人惊讶的一行是
使用DataType1=decltype(t().data());//int*

…但这仍然很正常,成员函数可以在临时对象上调用,而不被视为
const
这是成员函数和自由函数之间的另一个重要区别。


例如,在C++98(pre-rvalue refs)中,不可能执行感兴趣的
std::ofstream(“file.txt”)。对于
begin
/
end
,通常不会注意到这一点,因为您永远不会在右值上使用它们。你会说
auto&&uuux=f();自动it=开始(uux),因此参数始终是左值。对于
数据
,人们可能会类似地认为没有大小的数据是无用的,因此您也需要一个中间左值。但也许您应该提交一个库问题。谢谢。我也想出了这个规则。但我不太明白这条规则的依据。非常量左值引用不能绑定到右值有什么原因吗?仍然可以通过其成员函数修改临时对象。我发现成员函数和自由函数之间的根本区别很有趣。(见我的答案)。你知道标准中有没有提到成员函数可以修改临时变量?这太糟糕了
std::data(T())
将右值传递给
data
,而不是右值引用。“这意味着您可以更改临时对象”-好吧,这就像右值引用的整个要点一样,允许您通过更改临时对象来窃取它们的本质。非常感谢您找到了非常具体的规则。
std::data(T())
template <class _Cont> constexpr
auto data(const _Cont& __c) -> decltype(__c.data()) { return __c.data(); }
#include<iostream>
struct A{
    void f() const{std::cout << "const member" << std::endl;}
    void f(){std::cout << "non const member" << std::endl;}
};

void f(A const&){std::cout << "const function" << std::endl;}
void f(A&){std::cout << "non const function" << std::endl;}

int main(){
    A().f(); // prints "non const member"
    f(A()); // prints "const function"
}