2016-11-28 88 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

相關問題