2016-11-28 8 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; 
}; 

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

に変更すると、コンパイルされて実行されます。スコット・メイヤーのblog postの印象の下には、TryPush(T && val)がユニバーサルなリファレンスであり、最初のコードスニペットに示されているようにそれを使用して、値を配列に移動して、lvalueまたはrvalueが関数に渡されます。公衆がPushの方法に直面しているとうまくいくように見えます。したがって、私は何が起こっているのか混乱しています。私はここで何かを逃しているにちがいありませんし、誰かが正確にそれが何であるかを明確にすることができるかどうか疑問に思いましたありがとう。

編集 は、あなたのコード内の普遍的な参照がありませんので、

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

あなたはTryPush' 'を呼び出すにはどうすればよいですか? – NathanOliver

答えて

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

あなたがvector<int> v; v.push_back(x);のような何かを書くだろう、と機能がまだ何の控除がないint&&を取るとして知られているこのコードを使用する:blog postあなたがリンクでは、この同様の例を参照してください。

ユニバーサルリファレンスは、テンプレートタイプが引数から導出されている場合にのみ発生します(型が参照タイプとして導出されるため機能します)。


あなたはTryPush(std::move(val))TryPush(val)を変更した場合(値渡しで)あなたの元のコードは、正常に動作します。あなたはもちろんの代わりにTryPushのための普遍的な参照の2つのオーバーロードT const &T&&を使用することができますが、その後は2間でいくつかのコードの重複を持っていると思います

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); 

:不必要な移動操作を排除するには、2つのオーバーロード、例えばを提供することができます体。

またあなたもでPushを置き換えることができます:

template<typename U> 
void Push(U&& val) 
{ 
    while (!TryPush(std::forward<U>(val))); 
} 
+0

これはあなたがそれを設定することを提案する方法でしょうか?内部的に 'bool TryPush(T val)'を呼び出す2つのパブリックフェーシングメソッド 'void Push(T && val)'と 'void Push(const T&val)'を持ちます。このようにして心配はありますか? – cogle

+0

@cogle私は例を展開しました –

+0

'std :: forward(val)'は 'std :: forward (val)'であるべきですか? – aschepler

関連する問題