当实参匹配两个重载函数时,Rvalue reference参数是否优先于Lvalue reference参数?
问题:右值引用参数在重载匹配中是否优先于左值引用参数?
问题背景
当实参同时匹配两个重载函数时,右值引用(Rvalue reference)参数是否优先于左值引用(Lvalue reference)参数?
示例代码
#include <iostream> #include <cstdint> #include <cstring> class String{ public: String() = default; String( const char * string){ printf("Created!\n"); m_size=strlen(string); m_data=new char[m_size]; memcpy ( m_data, string , m_size) ; } // 若调用Entity的第一个构造函数,会触发该拷贝构造函数 String(const String& otherObject ){ printf("Copied!\n"); m_size=otherObject.m_size; m_data=new char[m_size]; memcpy ( m_data, otherObject.m_data , m_size); } // 若调用Entity的第二个构造函数,会触发该移动构造函数 String(String&& AutoTempObject){ printf("Moved!\n"); m_size=AutoTempObject.m_size; m_data=AutoTempObject.m_data; AutoTempObject.m_size=0; AutoTempObject.m_data=nullptr; } ~String(){std::cout<<"Destroyed!\n"; delete[] m_data; } void Print1(){ for (uint32_t i = 0 ; i < m_size ; i++){ std::cout << m_data[i]; } std::cout<< '\n'; } private: char * m_data; uint32_t m_size; }; class Entity{ public: // Entity的第一个构造函数 Entity(const String& StringObject) : m_name(StringObject) {} // Entity的第二个构造函数 Entity(String&& StringObject) : m_name( std::move(StringObject) ) {} void print(){ m_name.Print1(); } private: String m_name; }; int main(){ // 该声明会先调用Entity的某个构造函数,再相应触发String的某个构造函数 Entity e1(String("StackOverFlow")); }
观察与疑问
- 移除Entity的第2个构造函数时,程序会调用Entity的第1个构造函数;
- 同时保留Entity的两个构造函数时,程序会调用第2个构造函数;
- 由上述两点可知,实参
String("StackOverFlow")同时匹配Entity两个构造函数的参数; - 但实例化Entity对象时并未触发编译错误,而是优先调用了第2个构造函数,请问该现象的原因是什么?
解答
这是C++重载决议机制的规则导致的,核心逻辑是编译器会优先选择与实参匹配度更高的重载函数:
- 实参的类型属性:
String("StackOverFlow")是一个临时对象,属于右值。它既可以绑定到const String&(const左值引用),也可以绑定到String&&(右值引用)。 - 匹配优先级差异:根据C++标准,右值绑定到右值引用属于精确匹配,不需要任何隐式转换或限定符调整;而绑定到const左值引用是一种兼容性匹配,优先级低于精确匹配。因此编译器会优先选择接受右值引用的构造函数(即Entity的第二个构造函数)。
- 无右值引用重载时的降级逻辑:当你移除Entity的第二个构造函数后,编译器没有更匹配的选项,才会退而求其次选择接受const左值引用的构造函数,这就是此时程序调用第一个构造函数的原因。
结合你的代码场景:
- 保留两个构造函数时,临时右值
String("StackOverFlow")匹配Entity(String&&),随后通过std::move(StringObject)触发String的移动构造函数; - 移除第二个构造函数时,只能匹配
Entity(const String&),进而触发String的拷贝构造函数。
内容的提问来源于stack exchange,提问作者Crackie
相关产品推荐
相关产品推荐

