gpt4 book ai didi

c++ - 为成员函数生成必要的引用限定重载

转载 作者:行者123 更新时间:2023-12-05 05:30:13 25 4
gpt4 key购买 nike

我有这门课:

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); }
}

我想知道,对于这样一个简单的成员函数,我应该什么时候提供必要的ref-qualified过载。

使用实际代码,我可以编译并运行以下代码:

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- 为什么我可以编译第二个 REQUIRE包含带有 rvalue 的调用?

现在我要更改 len()对此的成员函数:

[[nodiscard]]
consteval int len() const& noexcept { return sizeof(array) / sizeof(T); }

2- 为什么我可以用 const& 编译两者?我想它们是两种不同的 ref-qualified 用法。我假设我可以用第一个电话调用电话,即 lvalue , 但不明白为什么我可以编译第二个定义了 len()方法为 const& .

上次更改:

[[nodiscard]]
consteval int len() const&& noexcept { return sizeof(array) / sizeof(T); }

最后,我在 a.get<I>() 上遇到编译器错误.

'this' argument to member function 'len' is an lvalue, but function has rvalue ref-qualifier
REQUIRE( a.len() == 5 );

如果我注释掉那行代码然后运行就完美了:

REQUIRE( collections::Array<int, 1>{1}.len() == 1 );

而且我还可以使用 std::move(a)执行a的类型转换到rvalue reference并编译代码。但我不想那样做。

  • 根据 ref-qualified 对这些示例进行编码的正确方法是什么?重载?
  • 不要忘记上面例子中的问题

编辑:

我将添加另一个成员函数,它可能会根据 ref-qualified 实现(或者我认为可能发生的情况)做不同的事情:

template <size_t I>
requires concepts::AccessInBounds<I, N>
constexpr T get() const noexcept {
return array[I];
}

template <size_t I>
requires concepts::AccessInBounds<I, N>
constexpr T& get() const& noexcept {
return array[I];
}

最佳答案

对于问题 1:为什么不呢?规则与左值相同:无论对象的常量性如何,都可以调用 const 成员函数。

对于问题 2:因为它意味着与具有 const& 函数参数相同:可以使用任何左值或右值调用该函数。它的存在主要是为了让您区分左值和右值重载:

class Array {
// These two declarations would be ambiguous for Array rvalues
// int len() const;
// int len() &&;

// These are not: your test expressions will use different overloads
int len() const&;
int len() &&;
};

您编辑中的两个函数对于左值和右值也是不明确的。一个激励性的例子更像是这样:假设我的类为某些资源提供功能,这些资源复制起来可能很昂贵,但移动起来更便宜,比如 std::vector。

template<class T>
class VectorView {
std::vector<T> vector;

public:
// ...

constexpr std::vector<T> const& base() const noexcept { return vector; }
};

现在,此类的用户无法将 vector 数据的所有权从 View 对象传回,即使这在对右值调用 base() 函数时很有用。因为避免为您不需要的东西付费符合 C++ 的精神,您可以通过添加一个右值限定的重载来实现这一点,该重载使用 std::move 返回一个右值引用。

因此,是否需要这种重载的答案视情况而定,不幸的是,这也符合 C++ 的精神。如果您正在为标准库实现类似于我的示例类的东西,那么您当然会这样做,因为它基于 std::ranges::owning_view。 .正如您在该页面上看到的那样,它涵盖了所有四种可能的 base()。如果您只是使用对源范围的引用,那么从该对象移动将是意外且不合适的,因此相关的 ref_view只有一个像我写的那样的 const base() 函数。

编辑 至于移动语义,数组和 vector 之间的区别在于 Array<T,N>基于T[N] , 而 std::vector<T>基于T* .移动数组需要N次移动操作(线性时间复杂度),移动是否是对拷贝的改进取决于T。另外,它需要2N个元素的内存空间。另一方面,一个 vector 只需要三个指针来完成它的工作,所以它可以在常数时间内移动,而复制仍然需要线性时间。

简而言之,这种潜在的 yield 是移动语义和右值引用的基本原理。还具有 && 限定成员函数的能力完善了此语言功能,但不如移动构造函数和赋值函数重要。我还找到了 this question 的答案很有用,因为它们提供了更多引用限定重载的示例。

关于c++ - 为成员函数生成必要的引用限定重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74760736/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com