我正在VS 2015 Community Edition中运行以下所有代码。

当我尝试实现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 &&)':无法将参数1从'int'转换为'int && 。令我困惑的是,如果将代码更改为
#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);
}

最佳答案

您的代码中没有通用引用。在您链接的blog post中,看到以下类似示例:



要使用此代码,您需要编写类似于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)) );
}

09-06 20:50