2016-11-28 115 views
2

我在VS 2015 Community Edition中运行以下所有代码。通用引用:无法将参数从'int'转换为'int &&'

当我尝试执行在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; 
}; 

每当我试图编译此代码我碰到下面的错误布尔RingBuffer :: TryPush(T & &):不能转换从参数1 '诠释' 到'廉政& &。令我困惑的是,如果将代码更改为

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

它编译并运行。我在斯科特迈尔的blog post的印象下,TryPush(T && val)是一个通用的引用,我应该能够使用它,如第一个代码片段所示,然后将值移入数组,从而确保代码工作,无论是左值还是右值被传递给函数。它似乎工作,如果它的公众面临Push方法,因此我有点困惑,究竟是怎么回事。我一定在这里错过了一些东西,并想知道是否有人能澄清究竟是什么。谢谢。

编辑 调用像这样

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

你怎么称呼'TryPush'? – NathanOliver

回答

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))); 
} 
+0

这是你建议设置它的方式吗?有两个面向公众的方法'void Push(T && val)'和'void Push(const T&val)',它们在内部都调用'bool TryPush(T val)'。这样做有什么担忧吗? – cogle

+0

@cogle我扩大了示例 –

+0

不应该'std :: forward(val)'是'std :: forward (val)'? – aschepler