我在VS 2015社区版中运行以下所有代码。
当我尝试实施Code Review中向我建议的建议时,我的代码出错了。我遇到问题的部分是将TryPush
的参数更改为TryPush(T&& val)
。
#pragma once
#include <atomic>
#include <memory>
template <typename T> class RingBuffer {
public:
/*
Other functions
*/
void Push(T val) {
while (!TryPush(val));
}
private:
/*
Other functions
*/
//Private Member Functions
bool TryPush(T && val) {
const std::size_t current_write = write_position.load(std::memory_order_acquire);
const std::size_t current_read = read_position.load(std::memory_order_acquire);
const std::size_t next_write = increment_index(current_write);
if (next_write == current_read) { return false; }
_ring_buffer_array[current_write] = std::move(val);
write_position.store(next_write, std::memory_order_release);
return true;
}
std::size_t increment_index(std::size_t index) {
return (index + 1) % _buffer_capacity;
}
//Private Member Variables
std::atomic<std::size_t> read_position = 0;
std::atomic<std::size_t> write_position = 0;
std::size_t _buffer_capacity;
std::unique_ptr<T[], RingBufferFree> _ring_buffer_array;
};
每当我尝试编译此代码时,我都会收到以下错误 bool RingBuffer :: TryPush(T&amp;&amp;)&#39;:无法转换参数1来自&#39; int&#39;到&#39; int&amp;&amp; 。令我困惑的是,如果将代码更改为
#pragma once
#include <atomic>
#include <memory>
template <typename T> class RingBuffer {
public:
/*
Other functions
*/
void Push(T && val) {
while (!TryPush(val));
}
private:
/*
Other functions
*/
//Private Member Functions
bool TryPush(T val) {
const std::size_t current_write = write_position.load(std::memory_order_acquire);
const std::size_t current_read = read_position.load(std::memory_order_acquire);
const std::size_t next_write = increment_index(current_write);
if (next_write == current_read) { return false; }
_ring_buffer_array[current_write] = std::move(val);
write_position.store(next_write, std::memory_order_release);
return true;
}
std::size_t increment_index(std::size_t index) {
return (index + 1) % _buffer_capacity;
}
//Private Member Variables
std::atomic<std::size_t> read_position = 0;
std::atomic<std::size_t> write_position = 0;
std::size_t _buffer_capacity;
std::unique_ptr<T[], RingBufferFree> _ring_buffer_array;
};
它编译并运行。我受到了Scott Meyer的blog post的印象,TryPush(T && val)
是一个通用参考,我应该可以使用它,如第一个代码片段所示,然后将值移动到数组因此确保代码工作,无论是否将左值或右值传递给函数。它似乎是公共面临Push
方法的工作,因此我对发生的事情感到困惑。我必须在这里遗漏一些东西,并想知道是否有人可以澄清究竟是什么。谢谢。
修改 这样称呼
RingBuffer<int> r(50);
for (int i = 0; i < 20; i++) {
r.Push(i + 1);
}
答案 0 :(得分:5)
您的代码中没有通用引用。在您关联的blog post中,请参阅此类似示例:
template <class T, class Allocator = allocator<T> > class vector { public: ... void push_back(T&& x); // fully specified parameter type ⇒ no type deduction; ... // && ≡ rvalue reference };
要使用此代码,您可以编写类似vector<int> v; v.push_back(x);
的内容,并且该函数已知为取int&&
,因此没有扣除。
只有在从参数推断出模板类型时才会发生通用引用(并且它们起作用,因为类型可以推断为引用类型)。
如果您将TryPush(val)
更改为TryPush(std::move(val))
,原始代码(带有值传递)就可以正常工作。为了消除不必要的移动操作,您可以提供两个重载,例如:
void Push(T && val) { while (!TryPush(std::move(val))); }
void Push(T const& val) { while (!TryPush(val)); }
private:
template<typename U>
bool TryPush(U&& val)
{
// preparation logic...
_ring_buffer_array[current_write] = std::forward<U>(val);
您当然可以使用两个重载T const &
和T&&
而不是TryPush
的通用引用,但是您在这两个主体中会有一些代码重复。
您甚至可以将Push
替换为:
template<typename U>
void Push(U&& val)
{
while ( !TryPush(std::forward<U>(val)) );
}