lundi 28 novembre 2016

Universal Reference: Cannot convert parameter from 'int' to 'int &&'

I am running all code below in VS 2015 Community Edition.

I am getting error in my code when I attempt to implement a suggestion that was suggested to me in Code Review. The part that I am having trouble with is changing the arguments to TryPush to be 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;
};

Whenever I attempt to compile this code I get the following error bool RingBuffer::TryPush(T &&)': cannot convert argument 1 from 'int' to 'int &&. What confuses me is that if change the code to

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

It compiles and runs. I was under the impressions from Scott Meyer's blog post that TryPush(T && val) is a Universal reference and I should be able to use it as is shown in the first code snippet and then move the value into the array thus ensuring the code works regardless of whether an lvalue or rvalue is passed into the function. It seems to work if it the public facing Push method and thus I am sort of confused as to what is going on. I must be missing something here and was wondering if anybody could clarify what exactly it is. Thanks.

Aucun commentaire:

Enregistrer un commentaire