21

c++ テンプレートで複数の typename 引数を使用するにはどうすればよいですか?

#ifndef _CALL_TEMP_H
#define _CALL_TEMP_H

#include <string>
#include <iostream>

template <typename Sig>
class Foo;

template <typename A, typename B>
class Foo
{
    public:
        void output() {
            std::cout << a_ << b_ << std::endl;
        }
        A a_;
        B b_;
};

template <typename A, typename B, typename C>
class Foo
{
    public:
        void output() {
            std::cout << a_ << b_ << c_ << std::endl;
        }
        A a_;
        B b_;
        C c_;
};

#endif

使用法:

int main()
{
    Foo<int ,int> doubleint;
    doubleint.a_ = 1;
    doubleint.b_ = 2;
    doubleint.output();
//  Foo<int , int , std::string> comp;
//  comp.a_ = 1;
//  comp.b_ = 2;
//  comp.c_ = "haha";
//  comp.output();
    return 0;
}

しかし、それはコンパイルされません。どうすればコンパイルできますか?

4

4 に答える 4

45

可変個引数テンプレートを使用してプライマリ テンプレートを宣言し、サポートされているテンプレート引数の数ごとに特化します。例えば:

#ifndef CALL_TEMP_H
#define CALL_TEMP_H

#include <iostream>

template <typename...> class Foo;

template <typename A, typename B>
class Foo<A, B>
{
public:
    void output() {
        std::cout << a_ << b_ << '\n';
    }
    A a_;
    B b_;
};

template <typename A, typename B, typename C>
class Foo<A, B, C>
{
public:
    void output() {
        std::cout << a_ << b_ << c_ << '\n';
    }
    A a_;
    B b_;
    C c_;
};

#endif

C++11 を使用できず、同様の表記法を保持したい場合は、テンプレートの既定の引数を使用して可変引数リストをシミュレートする必要があります。これにより、templare 引数の数が暗黙的に制限されますが、とにかくテンプレートを特殊化するため、この制限は実際には問題になりません。

別の表記法を使用することが許容される場合は、関数宣言のようなものを使用して、テンプレートをインスタンス化および特殊化することもできます。

template <typename> class Foo;

template <typename A, typename B>
class Foo<void(A, B)> {
    ...
};
template <typename A, typename B, typename C>
class Foo<void(A, B, C)> {
    ...
};
...
Foo<void(int, int)>                   f2;
Foo<void(int, int, std::string)> f3;

表記の変更が許容されるかどうかは、クラス テンプレートの使用方法によって異なります。ただし、C++ 11 を使用しない場合、可変個引数テンプレートのような理想的なソリューションは得られません。

ところで、使いすぎないstd::endl'\n'でください。行末を意味するために使用します。本当にストリームをフラッシュするつもりなら、 を使用してstd::flushください。また_CALL_TEMP_H、アンダースコアで始まり、その後に大文字が続くすべての名前と同様に、標準 C++ ライブラリに予約されている名前です。これらの名前を使用する明示的な許可がない限り、独自のコードでこれらの名前を使用しない__FILE__でください (たとえば、 and__LINE__は予約されていますが、それらの使用は許可されています)。

于 2013-11-12T07:44:53.240 に答える
3

テンプレートの複数のバージョンがある場合は、1 つのバージョンを特化する必要があります。異なる数の引数が必要な場合は、タグ クラスを使用して「この引数は引数ではありません」と指定し、それをデフォルトの引数として使用します。

あなたの場合、次のようなものが機能します(コンパイルおよびテスト済み):

#include <iostream>

// tag class indicating "no member in this place"
struct nothing {};

template <typename A, typename B, typename C = nothing> // <- note default arg.
class Foo;

template <typename A, typename B>
class Foo<A, B, nothing> // <- note specialization
{
    public :
        void output() {
            std::cout << a_ << b_ << std::endl;
        }

        A a_;
        B b_;
};

template <typename A, typename B, typename C>
class Foo
{
    public :
        void output() {
            std::cout << a_ << b_ << c_ << std::endl;
        }

        A a_;
        B b_;
        C c_;
};

int main()
{
    Foo<int, int> doubleint;
    doubleint.a_ = 1;
    doubleint.b_ = 2;
    doubleint.output();

    Foo<int, int, int> tripleint;
    tripleint.a_ = 1;
    tripleint.b_ = 2;
    tripleint.c_ = 3;
    tripleint.output();
}

これは本質的にboost::tuple<>/std::tuple<>の再発明であることに注意してください。これについては必ず読んでください。

于 2013-11-12T07:40:35.710 に答える
0

特殊化と同じクラス名のオーバーロードを混同していると思います。複数のテンプレート引数を持つ同じ名前のクラスを作成することはできません。

于 2013-11-12T07:40:03.040 に答える
0

テンプレート引数の数が異なる同じクラスを複数回定義することはできないため、コンパイルされません。

サポートするテンプレート パラメーターの最大数がわかっている場合は、部分的な特殊化を使用できます。

// main template
template <typename A, typename B = void, typename C = void>
struct Foo
{
    void output() { std::cout << a_ << b_ << c_ << std::endl; }
    A a_;
    B b_;
    C c_;
};

// Partial specialisation for two parameters
template <typename A, typename B>
struct Foo<A, B, void>
{
    void output() { std::cout << a_ << b_ << c_ << std::endl; }
    A a_;
    B B_;
};

// Partial specialisation for one parameter
template <typename A>
struct Foo<A, void, void>
{
    void output() { std::cout << a_ << std::endl; }
    A a_;
};

C++11 を使用している場合、別のオプションは可変個引数テンプレートを使用することです。

于 2013-11-12T07:49:04.480 に答える