13

クラステンプレートのテンプレートコンストラクター-2番目のパラメーターのテンプレート引数を明示的に指定する方法は?

コンストラクター2のテンプレート引数を明示的に指定しようとすると、コンパイルエラーが発生します。コンストラクター2を明示的に呼び出したい場合は、どうすればよいですか。

これは、削除者のタイプを明示的に指定する場合のboost::shared_ptrの場合と同じ状況であることに注意してください。

注意:構築関数foo()の場合、明示的に指定すると正常に機能します。

注意:テンプレート引数の推論は通常は正常に機能するため、コンストラクター2に対して2番目のものを明示的に指定しなくても正常に機能することはわかっています。明示的に指定する方法に興味があります。

template<class T> class TestTemplate {
public:
    //constructor 1
    template<class Y> TestTemplate(T * p) {
        cout << "c1" << endl;
    }

    //constructor 2
    template<class Y, class D> TestTemplate(Y * p, D d) {
        cout << "c2" << endl;
    }

    template<class T, class B>
    void foo(T a, B b) {
        cout << "foo" << endl;
    }
};

int main() {
    TestTemplate<int> tp(new int());//this one works ok call constructor 1
    //explicit template argument works ok
    tp.foo<int*, string>(new int(), "hello");

    TestTemplate<int> tp2(new int(),2);//this one works ok call constructor 2

    //compile error when tried to explicit specify template argument for constructor 2
    //How should I do it if I really want to explicit call constructor 2?
    //TestTemplate<int*, int> tp3(new int(), 2); //wrong
    //TestTemplate<int*> tp3<int*,int>(new int(), 2); //wrong again

    return 0;
}
4

3 に答える 3

28

コードを修正すると、次のように機能します。

template<class T> class TestTemplate {
public:
    //constructor 1
    template<class Y> TestTemplate(Y * p) {
        cout << "c1" << endl;
    }

    //constructor 2
    template<class Y, class D> TestTemplate(Y * p, D d) {
        cout << "c2" << endl;
    }

    template<class A, class B>
    void foo(A a, B b) {
        cout << "foo" << endl;
    }
};

int main() {
    TestTemplate<int> tp(new int());

    tp.foo<int*, string>(new int(), "hello");

    TestTemplate<int> tp2(new int(),2);
}

Tクラステンプレートパラメーターコンストラクターテンプレートパラメーターには使用できません。しかし、あなたの質問に答えるために、[14.5.2p5]から:

明示的なテンプレート引数リストは関数テンプレート名の後に続き、変換メンバー関数テンプレートとコンストラクターメンバー関数テンプレートは関数名を使用せずに呼び出されるため、これらの関数テンプレートに明示的なテンプレート引数リストを提供する方法はありません。

したがって、コンストラクターのテンプレート引数を明示的に指定することはできません。

于 2012-10-21T22:01:09.603 に答える
10

コンストラクター自体には名前がなく、コンストラクターの構文がないため、コンストラクターのテンプレート引数を明示的に指定することはできません。

ただし、次の方法で、正しいテンプレート引数が推測されるようにすることができます。

  • 実際の引数をキャストする、および/または

  • 必要に応じて、型情報を運ぶためだけに「人工的な」追加の引数を導入する、および/または

  • ファクトリ関数を使用します。

たとえば、次のように定義できます

template< class Type > struct TypeCarrier{ typedef Type T; };

struct MyClass
{
    template< class Type >
    MyClass( TypeCarrier< Type > ) { ... }
};

...
MyClass o( TypeCarrier<int>() );

しかし、そのようなテクニックに夢中にならないでください。

代わりに、コンストラクターテンプレートの引数を明示的に指定する必要があることが明らかになった場合は、デザインが本当に適切かどうかを検討してください。

おそらく、それが何のためにあるのかを考えれば、もっと単純なデザインを使うことができますか?

于 2012-10-21T22:11:25.843 に答える
4

fooこれらのメンバー関数fooには名前があり、テンプレート引数はその名前の一部であるため、呼び出しのテンプレート引数を明示的に指定できます。

コンストラクターには名前がないため、コンストラクターでは機能しません。コンストラクターを(直接)呼び出すことはできません。もちろん、オブジェクトを作成するときにコンストラクターが呼び出されますが、呼び出しは生成されたコードです。

于 2012-10-21T21:56:14.153 に答える