2017-01-10 3 views
5

次のスニペットがコンパイルされる理由を理解するのが苦労しています。私はテンプレートクラスptr_to_member<T>を持っていて、メンバー関数へのポインタはTです。私はptr_to_member<my_class>を持つ新しいクラスmy_classを作成しています。私は、my_classが依然として定義されているので、後者がコンパイルエラーを引き起こすことを期待していました。どんな助けもありがとうございます。ありがとうございました。C++:クラスが完全に定義される前に、テンプレート引数としてのクラスの使用

#include <iostream> 

// this class simply stores a pointer to a member function of T 
template <class T> 
struct ptr_to_member { 

    using ptr_type = void (T::*)(); 
    ptr_type m_ptr; 

    ptr_to_member() 
    : m_ptr(&T::f){} 

    auto get_ptr() const { 
     return m_ptr; 
    } 
}; 

// my_class has a ptr_to_member<my_class> 
class my_class { 

    ptr_to_member<my_class> m_ptr_to_member; // why does this compile? 

public: 

    void g() { 
     auto ptr = m_ptr_to_member.get_ptr(); 
     (this->*ptr)(); 
    } 

    void f() { 
     std::cout << "f" << std::endl; 
    } 
}; 

int main() { 

    my_class x; 
    x.g(); 

} 

答えて

0

クラスを定義するときに、そのクラスは前方宣言されたものとして使用できます。 ptr_to_memberは、そのメソッドの1つをインスタンス化するまでTへのポインタしか使用しないので、それは文句を言わない。ポインタではなくTというメンバを追加してみると、失敗したことがわかります。直感的な方法は、TTというポインタを使用するかどうかを知る必要はなく、Tの1つのタイプのみです。ポインターは、逆参照するまでポインターに関係なく同じ方法で動作します。

template <class T> 
struct ptr_to_member { 

    using ptr_type = void (T::*)(); 
    ptr_type m_ptr; 

    ptr_to_member() 
     : m_ptr(&T::f) {} 

    auto get_ptr() const { 
     return m_ptr; 
    } 

    T member; // Add this and see that it fails to compile 
}; 

あなたは前方宣言された型を使用することはできませんときの詳細については、this answerを参照してください。

+0

'my_class'がその定義内で不完全な型であるとすれば、私はポインタや参照を使用することしか許されておらず、メソッドは使用できないと考えました。だから私が 'my_class'へのポインタを持っていれば、' my_class'が定義される前に 'my_class_ptr-> f()'を使うことができません。したがって、 'ptr_to_member'のコンストラクタで'&T :: f'を使用すると問題が生じることを期待していました...何が欠けていますか? – linuxfever

+0

この場合のテンプレートは赤ん坊です。メソッドの定義は、クラス宣言が完了した後でのみ調べられます。私は[この回答](http://stackoverflow.com/a/13095136/7359094)は私がコメントでできるよりもそれを説明できると思います。 –

+0

ありがとう、私は今それを得ると思います – linuxfever

関連する問題