2011-12-23 21 views
4

read1のコンパイラはなぜ一致しませんか? read1read2の違いはわかりません。 Fooクラスのようなネストされたtypedefテンプレートには制限がありますか?テンプレート関数の引数としてC++のテンプレートtypedef

template<typename T> 
class Handle{}; 

class Foo{ 
public: 
    typedef Handle<Foo> Handle; 
}; 


template<typename T> 
void read1(typename T::Handle){} 

template<typename T> 
void read2(Handle<T>){} 


int main(int argc, char** argv) 
{ 
    Foo::Handle f1;  
    read1(f1); 

    Foo::Handle f2; 
    read2(f2); 
} 

G ++コンパイラの出力、(G ++ 4.4.5)

g++ -c -I. main1.cpp 
main1.cpp: In function ‘int main(int, char**)’: 
main1.cpp:37: error: no matching function for call to ‘read1(Handle<Foo>&)’ 
+0

冗長な「内部」名前空間を削除し、例を簡潔にしました。 – Xeo

+0

G ++ 4.4.5で編集したコードは 'g ++ -c main.cpp main.cpp:8:error: 'typedef class Handleの宣言 Foo :: Handle' main.cpp:3:エラー:変更'int handle(int、char **)': main.cpp:関数 'int main(int、char **)'内で: 'handle'の意味 'handle'の意味は 'handle1'(ハンドル &) '' –

答えて

4
Foo::Handle f1;  
read1(f1); 

read1に渡される型はFooではなくHandle<Foo>です。

テンプレートは継承されません。 Handle<Foo>はFooではない別のクラスであるため、Handle<Foo>::Handleはありません。

3
template<typename T> 
void read1(typename T::Handle) 
{ 
} 

まず、あなたはread1<Foo>(f1)のような明示的なテンプレートパラメータを提供せずに、この関数を呼び出すことができることはありません。 SFINAEにお読みください。

第2に、コンパイラはどのようにしてを見つけるのですか?Tは何ですか?おそらく書いた可能性のあるすべてのクラスのすべてのネストされたtypedefをテストする必要があります。不可能だと思う?そうです。

+2

あなたが書くことができるすべてのクラスをテストする必要はありません。 read1呼び出しの時点で定義されたクラスをテストするだけでよい。可能です(コンパイラがテンプレートを処理するために必要なものと比較して簡単ですが)。標準では実行できません。 –

+0

なぜread2のように引数を見つけることができますか?それだけでFooをテストする必要があります。他のタイプはありません。 –

+0

ポイントで定義されたすべてのクラスをテストするだけでなく、すべてのテンプレートインスタンス化も可能です(テンプレートフォームでも可能です)。しかし、それはどのようにして曖昧さを解決するでしょうか?通常、プログラマはこれらの問題を修正する必要がありますが、この場合は完全に無関係なコードの変更(異なる名前空間とすべて)によってあいまいさが生じる可能性があります。 @José:この単純な例ではfooをテストすればよいかもしれませんが、ほとんどのscneariousは複雑であり、ほとんどの時間で動作しない言語機能はあまり一般的ではありません – Grizzly

関連する問題