C++成员函数ref-qualified重载适用场景及编译问题咨询
C++成员函数ref限定符的疑问与正确用法
首先给出定义的Array模板类:
template<typename T, size_t N> class Array { private: T array[N]; public: template <typename... InitValues> constexpr Array(InitValues... init_values) : array{ init_values... } {} [[nodiscard]] consteval int len() const noexcept { return sizeof(array) / sizeof(T); } };
测试代码可正常编译运行:
constexpr collections::Array a = collections::Array<long, 5>{1L, 2L, 3L}; SECTION("length of the array") { REQUIRE( a.len() == 5 ); REQUIRE( collections::Array<int, 1>{1}.len() == 1 ); }
疑问解答
疑问1:为什么右值对象调用无ref限定的len()能通过编译?
C++标准规定,没有ref限定符的成员函数,对调用对象的值类别没有限制——左值、右值都可以调用这类成员函数。这是默认的成员函数调用规则,只要函数的cv限定(const/volatile)和对象的cv属性匹配即可。
疑问2:为什么const&版本的len()能同时被左值和右值调用?
这是因为右值可以被隐式绑定到const左值引用上。当成员函数被const&限定后,函数的this指针类型是const Array* const&,右值对象会被临时绑定到这个引用上,因此右值调用const&限定的成员函数是完全合法的。只有&&限定的成员函数才会拒绝左值调用。
ref限定重载的正确实现方式
1. 像len()这类无状态依赖的简单函数
len()返回的是编译期常量,完全不依赖对象的运行时状态,也不会修改对象,更不需要区分调用对象的左/右值。这类函数不需要添加任何ref限定符,保持最初的const noexcept版本即可,既能满足所有调用场景,代码也更简洁。
2. 像get()这类需要返回引用/值的函数
对于需要返回元素引用或值的get(),需要根据调用对象的值类别做针对性重载,确保返回值的语义正确:
template <size_t I> requires concepts::AccessInBounds<I, N> constexpr const T& get() const& noexcept { return array[I]; } template <size_t I> requires concepts::AccessInBounds<I, N> constexpr T& get() & noexcept { return array[I]; } template <size_t I> requires concepts::AccessInBounds<I, N> constexpr T&& get() && noexcept { return std::move(array[I]); }
const&版本:供const左值对象调用,返回const引用,保证只读&版本:供非const左值对象调用,返回可修改的引用&&版本:供右值对象调用,返回右值引用,允许调用者移动元素,避免不必要的拷贝
内容的提问来源于stack exchange,提问作者Alex Vergara
相关产品推荐
相关产品推荐

