通用引用:无法将参数从'int'转换为'int &&'

cog*_*gle 3 c++ c++11

我正在运行VS 2015 Community Edition中的所有代码.

当我尝试实现在Code Review中向我建议的建议时,我的代码中出现错误.那我有麻烦的部分被改变的参数TryPushTryPush(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;
};
Run Code Online (Sandbox Code Playgroud)

每当我尝试编译此代码时,我得到以下错误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;
};
Run Code Online (Sandbox Code Playgroud)

它编译并运行.我受到Scott Meyer 博客文章的印象,这TryPush(T && val)是一个Universal参考,我应该能够像第一个代码片段中所示那样使用它,然后将值移动到数组中,从而确保代码无论是左值还是左值都能正常工作rvalue传递给函数.它似乎是有效的,如果它是面向公众的Push方法,因此我对发生的事情感到困惑.我必须在这里遗漏一些东西,并想知道是否有人可以澄清究竟是什么.谢谢.

编辑这样 调用

RingBuffer<int> r(50);
for (int i = 0; i < 20; i++) {
    r.Push(i + 1);
}
Run Code Online (Sandbox Code Playgroud)

M.M*_*M.M 5

您的代码中没有通用引用.在您链接的博客文章中,请参阅此类似示例:

template <class T, class Allocator = allocator<T> >
class vector {
public:
    ...
    void push_back(T&& x);       // fully specified parameter type ? no type deduction;
    ...                          // && ? rvalue reference
};
Run Code Online (Sandbox Code Playgroud)

要使用这个代码,你会写一些类似的东西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);
Run Code Online (Sandbox Code Playgroud)

你当然可以使用两个重载T const &T&&不是通用引用TryPush,但是你会在两个主体上有一些代码重复.

你甚至可以替换Push为:

template<typename U>
void Push(U&& val)
{
    while ( !TryPush(std::forward<U>(val)) ); 
}
Run Code Online (Sandbox Code Playgroud)