2017-11-20 9 views
2

現在、ライブラリの作成中です。遅延呼び出しとgcc、clang、MSVCを使用して動作するコールバックの登録を容易にします。インタフェース内の転送参照を含むオーバーロードが発生する

私は非常に奇妙なものを見つけました。私は2つのオーバーロードを持つ関数を持っていて、関数がインターフェイスで定義されている場合にのみエラーが発生します。 gcc 6.3.0-18とclang 3.8.1-24を使用して同じエラーが発生します。

保護されたコンストラクタを使用してGoogleが推奨するインターフェイスを作成します。

#include <queue> 
#include <memory> 

template <class T> 
class IA { 
public: 
    virtual ~IA() = default; 
    // virtual bool push(const T& souce) = 0; /* Issue */ 
    virtual bool push(T&& source) = 0; 
protected: 
    IA() = default; 
}; 

私はstd::unique_ptrは、

int main() { 
    A<std::unique_ptr<float> > a; 
    return 0; 
} 

すべてが正常に動作します使用してクラスをインスタンス化した場合、今インターフェース

template <class T> 
class A : public IA<T> { 
public: 
    ~A() override {}; 

    bool push(const T& source) { 
    m_queue.push(source); 
    return true; 
    } 

    bool push(T&& source) { 
    m_queue.push(std::move(source)); 
    return true; 
    } 
private: 
    std::queue<T> m_queue; 
}; 

を実装するクラス。私はインターフェイスからプロトタイプbool push(const T& soruce)で関数のコメントを外していない限り、コメントを外します。その後、私はエラーを取得します。

/usr/include/c++/6/ext/new_allocator.h:120:4: error: use of deleted 
function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const 
std::unique_ptr<_Tp, _Dp>&) [with _Tp = float; _Dp = 
std::default_delete<float>]’ 
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); } 

私はstd::unique_ptr年代をコピーすることはできませんが、機能は実装だけに存在している場合は、なぜエラーが表示されないという事実を十分に認識しています。

+0

私は問題がコピーコンストラクタに関連していると思う、unique_ptrはコピーコンストラクタまたはassigmentを許可します。 – JTejedor

+0

私はそれを知っています。奇妙なことは、インターフェイスから関数を削除するとエラーが消えることです。すべてはまだ動作します。オーバーロードを維持したい理由は、後方互換性のためです。 –

+0

少し実験した後、問題はコンパイラによってテンプレート関数が評価されるときだと私は思う。行にコメントが付いていない場合は、オブジェクトの作成時にテンプレートメンバー関数が評価されるため、オブジェクトの宣言時にエラーが表示されます。しかし、コピー関数メンバがコード内にない場合、メンバ関数は使用時に評価されます。 – JTejedor

答えて

3

std::unique_ptr<T>のようなコピー可能ではないタイプのテンプレートをインスタンス化すると、コンパイラはこれについて不満を持ちます。テンプレート解決がC++で動作する方法は、monomorphizationというプロセスを通して行われます。コンパイラーは、各テンプレート・インスタンスごとに異なるタイプを作成します。 A<int>およびA<float>は、単形化が完了した後は無関係である。一方、これは、コンパイラが実際に使用する型のインスタンスのみを作成することを意味します。

Tにコピー不可能な型を使用しない限り、またはコピーコンストラクタを呼び出すコードのコメントを外してコメントを外している場合は、bool push(const T& source)です。

それに加えて、コンパイラは、未使用であると推測できるときには、最初のプッシュメソッドをコンパイルしていないようです(see live example)。これは、解析可能であるが間違ったC++コードを含む可能性があることを意味します。メソッドが仮想であれば、コンパイラはそれが使用されていない(vtableを介して呼び出すことができる)ことをもはや推測できないため、メソッドのコードを生成してエラーに遭遇する必要があります。

+1

コピーできないタイプを使用してもソースがコンパイルされます。 'std :: unique_ptr 'を呼び出し、実装に 'bool push(const T&source)'関数を保持してください。それは私が奇妙に感じるものです。私は 'std :: enable_if'と' is_copy_constructible'を使って回避策を作りました。 –

+0

私は答えを更新しました。 – jupp0r

+1

Hmm。私にとっては驚きです...私は、別のテンプレート引数 'bool = std :: is_copy_constructible'をインターフェースと実装の両方に追加することで、私の問題を解決しました。再度、感謝します。テンプレートの場合でも、インターフェイスを定義することが理にかなっている理由を示しています。 –

関連する問題