2012-06-21 7 views
8

非型名テンプレートパラメータとしてスーパークラスの機能を渡す

int main(){ 
    void (B::*f)()=&B::f;  
} 

作業が、

Call<B,&B::f> a; 

could not convert template argument ‘&A::f’ to ‘void (B::*)() 
を訴えないんなぜあなたは

struct A{ 
    void f(){} 
}; 


struct B:public A{ 
}; 


template<typename C,void (C::*f)()> 
struct Call{ 

    void operator()(C* c){ 
    (c->*f)(); 
    } 
}; 

を持っていると仮定

同様

const void (B::*f)()=&B::f; 

を(Call<A,&A::f>は明らかに動作します)間違っている正確に何

cannot convert ‘void (A::*)()’ to ‘const void (B::*)()’ in initialization 

答えて

4
void (B::*f)()=&B::f; 

動作するため、暗黙的な変換を適用されているA::f()の別名です。

4.11(2)

Bは、「タイプの prvalueにメンバーへのポインタを変換することができるクラス型であり、「タイプCV TのBのメンバーへのポインタ」型のprvalue DはB.

の派生クラス(項10)であるタイプCV T」、Dの値が、標準はnullptr_t変換以外テンプレート引数のメンバ関数へのポインタのための任意の変換を可能にしません。

14.3。2

メンバ関数へのポインタ型の非型テンプレートパラメータの場合、テンプレート引数が 型std :: nullptr_tの場合、ヌルメンバポインタ変換(4.11)が適用されます。それ以外の場合は、変換なし が適用されます。 template-argumentがオーバーロードされたメンバー関数のセットを表す場合、一致するメンバー 関数が集合(13.4)から選択されます。

+0

よかった、ありがとう!ちなみに、const void(B :: * f)()= &B::f;も受け付けていません。 –

+0

@Fabio:void(B :: * const f)()=&B :: fはうまく動作します:)。 const void(B :: * f)()はconst void値を返すメソッドへのポインタを意味するので、メソッドのシグネチャは後者の場合には不一致です。 – user396672

+0

申し訳ありませんが、あなたは正しいです、ありがとう! –

0

エラー状態、void (A::*)()void (B::*)()は異なるタイプのを提供します。

このケースでは、やりやすいはずですが、一般的なケースははるかに複雑になります。 Aに複数の仮想関数があり、Bに複数の継承があった場合どうなるかを考えてください。メンバ関数へのポインタは、そのようなことを考慮する必要があるため、非常に複雑な獣です。 B::f()が実際に存在するように

struct B:public A{ 
    void f() { A::f(); } 
}; 

:あなたがにBを変えることができるhttp://blogs.msdn.com/b/oldnewthing/archive/2004/02/09/70002.aspx

を見てみましょう。今B::f()は明らかにタイプvoid (A::*)()のではなく

void (B::*f)() 

void (A::*f)() 

からvoid (B::*)()

+0

私はあなたの意見に完全に同意します。私の不思議は、どうしてボイド(B :: * f)()= &B::f;を持つことが可能なのかです。 なお、const void(B :: * f)()= &B::f; も受け付けません。 –

+0

@FabioDallaLibera異なる規則があります。テンプレートパラメータは、代入演算子が変換可能な型を使用できるのと同じ型でなければなりません。あなたは 'std :: vector a;を期待しません。 std :: vector b; a = b; '' char''が '' int''に暗黙的に変換できるので、単に動作します。 – IronMensan

関連する問題