2011-07-24 11 views
1

テンプレートプログラミングをC++で教えているので、私の前提のいくつかが間違っている可能性があります。テンプレートテンプレートをテンプレートに含めることを特化する

STLリストを関数のテンプレートパラメータとして使用しようとしています。この関数はあらゆる種類のデータ型で使用されるはずですので、元の宣言でtemplate<template<> class T>ではなく関数をtemplate<class T>と定義しました。私は今、それをテンプレートクラスをサポートするように特化したいと思っています。

template<class T> 
void function(T param) 
{ 
    // do something with T 
} 

template<template <class T, class Allocator> class listPlaceholder> 
void function(std::list<T, Allocator> param) 
{ 
    // do something with every element in param (I actually need to know it's a list) 
    std::list<T, Allocator>::iterator current = param.begin(); 
    std::list<T, Allocator>::iterator end = param.end(); 

    do { 
    function<T>(*current); 
    } while (++current != end); 
} 

の問題は、私はそれがTAllocatorは、スコープで定義されていないことを述べている(GCCの下で)このコードをコンパイルしようとします。私の主な質問は、 "私はどのようにテンプレートクラスを専門にするのですか?"第2に、可能であれば、「どのようにテンプレートテンプレートパラメータを抽出するのですか?」

前述のように、私はテンプレートプログラミングを学んでいるので、明白な解決策は大歓迎です。

答えて

3

パラメータ

template<template <class T, class Allocator> class listPlaceholder, 
     class T, class Allocator> 
void function(listPlaceholder<T, Allocator> param) 
{ 
    // do something with every element in param (I actually need to know it's a list) 
    typename listPlaceholder<T, Allocator>::iterator current = param.begin(); 
    typename listPlaceholder<T, Allocator>::iterator end = param.end(); 

    do { 
    function<T>(*current); 
    } while (++current != end); 
} 

仮パラメータ・リストで使用した名前は意味を持ちません。実際にlistPlaceholderの使用を忘れてしまった。しかし、私はそれが偶然だったと仮定しています。

別のポスターによると、dependent namesという名前のため、typenameというキーワードも必要です。仮リスト内の名前は関数ポインタと比較し、無意味である理由については

:重要である

void f(void (*p)(int t, int allocator), int t, int allocator) { 
    p(t, allocator); 
} 

void g(int a, int b) { 
} 

int main() { 
    f(&g, 0, 1); 
} 

何がパラメータの種類のみである、と私はあまりにもvoid(*p)(int, int)を書かれている可能性があります。あなたの場合、重要なのは、両方のパラメータが型パラメータであることだけです。したがって、テンプレートテンプレートパラメータもtemplate<class, class> class listPlaceholderと完全に同等であると書くことができます。

最後に、ではなくfunctionであることを強調したいと思いますが、別のテンプレートでオーバーロードしました。だから、functionは、全く異なる2つの関数テンプレートです。

+0

他の2つのパラメータテンプレートクラスを開いたままで、 'std :: list'を特化するために' listPlaceholder'と 'std :: list'を使いました(例えば私も' std :: pair'を使っています) 。他のコメント作成者に言及したように、追加のテンプレートパラメータは、元の関数でこの変更された関数を使用できないことを意味します。 – fuseinabowl

+0

@fuseinabowl、そうですね。まあ、あなたが専門ではないので、あなたはそれをもっと専門にするために "開いたままにする"必要はありません。パラメータ化された 'std :: list 'の関数テンプレートは、関数テンプレートに対しては実行できない部分的な特殊化を必要とするため、特殊化できませんでした。 'std :: list'をそこに貼り付けるだけで、後で他のタイプのオーバーロードを追加することができます。コンパイラーは、コールで最も特殊なテンプレートを選択します(つまり、最も近いものが引数にマッチします)。 –

+0

私はまずそれを試しました - 私はそれをコード化する方法を正確にはうまくいけませんでした。私にテンプレート関数宣言のコードサンプルを教えてもらえますか? – fuseinabowl

0

使用typename

typename std::list<T, Allocator>::iterator current = param.begin(); 
typename std::list<T, Allocator>::iterator end = param.end(); 

そのiteratorが依存名ですので、それはiteratorが実際にタイプ、ない静的な値であることを知ることができるようにtypenameは、コンパイラによって必要とされるため。このFAQを読んで、これを詳細に知ることが

に加えて、あなたは関数テンプレートを書くべきであるとして:あなたはそれらを宣言したい

template <class T, class Allocator> 
void function(std::list<T, Allocator> param) 
{ 
    //code.. 
} 
+0

これは当てはまりますが、OPの質問で報告されたエラーの原因ではありません。 – templatetypedef

2

g++は実際にはここで正しいです。この範囲にTまたはAllocatorを宣言していません。あなたが持っているテンプレート宣言

template<template <class T, class Allocator> class listPlaceholder> 
    void function(std::list<T, Allocator> param) 

"私は引数として2つのクラスを取るクラステンプレートに対してパラメータ化されています。"と言っています。ただし、これらの引数の名前には、テンプレートの本文のどこにでもアクセスすることはできません。彼らは、プレースホルダとして主にそこにいる、と上記のテンプレート宣言は

template<template <class, class> class listPlaceholder> 
    void function(std::list<T, Allocator> param) 

これはどのように引数として別の関数を取り、通常のC++関数を宣言した場合、あなたがアクセスすることはできませんに似ていると等価ですパラメータの名前それは私はあなたがこのように見えるためにあなたのテンプレート関数のシグネチャを変更されて何をしたいのかと考えてい

void DoSomething(void function(int, int)) { 
    x = 5; // Error! 
} 

と同等なので

void DoSomething(void function(int x, int y)) { 
    x = 5; // Error! 
} 

:たとえば、これは違法である

template<class T, class Allocator> 
    void function(std::list<T, Allocator> param) 

これは「この関数は2つの型に渡ってパラメータ化されています。型とアロケータでパラメータ化されたstd::listの引数として渡されるとき、この関数の本体はth oseタイプはTAllocatorです。

+1

ありがとう、これはよく問題を説明します。これは、私が特殊化せずにこれらの余分なテンプレートパラメータで元の関数を再宣言しなければならないことを意味し、2つのテンプレート関数をリストに特化しますか?元の関数と混同されることなく、1つのテンプレートクラスで同じ結果を達成するにはどうしますか? – fuseinabowl

+0

一般的な「リスト以外のもの」関数とより特殊化された「リストのみ」関数を使いたい場合は、最初のバージョンを何らかの型 'T'をとるテンプレート関数として記述し、2番目の関数を上記。 C++では、オーバーロードの解決時に常により特殊化された関数が選択されます。 – templatetypedef

+0

ありがとう、それは非常に便利だった:) – fuseinabowl

関連する問題