是否可以在单个通用引用方法中实现 std::vector 的两个 push_back(..) 方法?
Is it possible to implement two push_back(..) methods of std::vector in a single universal reference method?
我正在尝试 std::vector
完全靠自己实现一些锻炼目的。我的问题是关于 push_back(..)
方法。此方法有两个重载,如下所示。
void push_back(const value_type& value);
void push_back(value_type&& value);
起初,我在两个不同的函数中实现了它们。对于前者,我选择复制构造具有给定值的新元素。对于后一个,我选择移动构造具有给定值的新元素。以下是我的实现:
template<class T>
void Vector<T>::push_back(const value_type& value)
{
if(size() == capacity()) // Size is about to surpass the capacity
grow(nextPowerOf2(capacity()), true); // Grow and copy the old content
new(data + sz++) value_type(value); // Copy construct new element with the incoming one
}
template<class T>
void Vector<T>::push_back(value_type&& value)
{
if(size() == capacity()) // Size is about to surpass the capacity
grow(nextPowerOf2(capacity()), true); // Grow and copy the old content
new(data + sz++) value_type(std::move(value)); // Move construct new element with the incoming
}
之后,我意识到我可以将这两个函数合并到一个采用通用引用的方法中,例如以下代码:
template<class T>
template<class U>
void Vector<T>::push_back(U&& value)
{
if(size() == capacity()) // Size is about to surpass the capacity
grow(nextPowerOf2(capacity()), true); // Grow and copy the old content
// Construct new element with the incoming
new(data + sz++) value_type(std::forward<U>(value));
}
我认为这个单一的方法可以处理我试图用两种不同的方法做的所有事情。有什么我想念的吗?这个手术以后会不会打扰我?我不寻求向后兼容,所以你可以省略它。
第二个版本不等同于第一个版本。
第一个参数是“对 T
的引用”,第二个参数 U
可以是任何类型,与 T
无关。
所以第二个版本实际上更 emplace_back
而不是 push_back
。它将采用任何值并尝试使用它构造 T
的实例(尽管通常 emplace_back
采用 pack 参数,以获得更大的灵活性)。
您可以使用 SFINAE 将 U
限制为与 T
兼容的类型,但这样代码可能会变得比仅具有两个单独的重载更复杂。
template<class T>
template<class U, typename std::enable_if_t<std::is_convertible_v<std::decay_t<U>, T>, int> = 0>
void Vector<T>::push_back(U&& value)
{
// . . .
例如,stdlibc++ 有两个单独的重载 vector::push_back
,但是 push_back(T&&)
只是 delegates 到 emplace_back
。所以也许你也可以这样做。
我正在尝试 std::vector
完全靠自己实现一些锻炼目的。我的问题是关于 push_back(..)
方法。此方法有两个重载,如下所示。
void push_back(const value_type& value);
void push_back(value_type&& value);
起初,我在两个不同的函数中实现了它们。对于前者,我选择复制构造具有给定值的新元素。对于后一个,我选择移动构造具有给定值的新元素。以下是我的实现:
template<class T>
void Vector<T>::push_back(const value_type& value)
{
if(size() == capacity()) // Size is about to surpass the capacity
grow(nextPowerOf2(capacity()), true); // Grow and copy the old content
new(data + sz++) value_type(value); // Copy construct new element with the incoming one
}
template<class T>
void Vector<T>::push_back(value_type&& value)
{
if(size() == capacity()) // Size is about to surpass the capacity
grow(nextPowerOf2(capacity()), true); // Grow and copy the old content
new(data + sz++) value_type(std::move(value)); // Move construct new element with the incoming
}
之后,我意识到我可以将这两个函数合并到一个采用通用引用的方法中,例如以下代码:
template<class T>
template<class U>
void Vector<T>::push_back(U&& value)
{
if(size() == capacity()) // Size is about to surpass the capacity
grow(nextPowerOf2(capacity()), true); // Grow and copy the old content
// Construct new element with the incoming
new(data + sz++) value_type(std::forward<U>(value));
}
我认为这个单一的方法可以处理我试图用两种不同的方法做的所有事情。有什么我想念的吗?这个手术以后会不会打扰我?我不寻求向后兼容,所以你可以省略它。
第二个版本不等同于第一个版本。
第一个参数是“对 T
的引用”,第二个参数 U
可以是任何类型,与 T
无关。
所以第二个版本实际上更 emplace_back
而不是 push_back
。它将采用任何值并尝试使用它构造 T
的实例(尽管通常 emplace_back
采用 pack 参数,以获得更大的灵活性)。
您可以使用 SFINAE 将 U
限制为与 T
兼容的类型,但这样代码可能会变得比仅具有两个单独的重载更复杂。
template<class T>
template<class U, typename std::enable_if_t<std::is_convertible_v<std::decay_t<U>, T>, int> = 0>
void Vector<T>::push_back(U&& value)
{
// . . .
例如,stdlibc++ 有两个单独的重载 vector::push_back
,但是 push_back(T&&)
只是 delegates 到 emplace_back
。所以也许你也可以这样做。