2

(おそらく)簡単な質問があります。テンプレートで使用される関数をいつ宣言する必要がありますか?次のコードが出力されます(gcc> = 4.1を使用)。

私のAオブジェクトを初期化する

初期化なし

gcc 4.0を使用すると、次のコードが出力されます。

私のAオブジェクトを初期化する

文字列オブジェクトを初期化する

#include <iostream>
#include <string>

template<typename T>
void init(T& t){
        std::cout << "no init" << std::endl;
}

// void init(std::string& t);

template <typename T>
void doSomething(T& t){
        init(t);
        // do some further stuff
}

void init(std::string& t){
        std::cout << "init my string object" << std::endl;
}


class A{

};

void init(A& t){
        std::cout << "init my A object" << std::endl;
}

int main(){
        A a;
        doSomething(a);
        std::string s("test");
        doSomething(s);
        return 0;
}

std :: stringとAの使用法の違いは何ですか?同じ振る舞いがあるべきではありませんか?

追加の前方宣言を使用すると正常に機能しますが、いつ必要になりますか?

乾杯、CSpille

4

1 に答える 1

4

インスタンス化ポイントの関数は、引数に依存するルックアップ(関数の引数に関連付けられた名前空間で関数をルックアップする)を使用してのみルックアップされます。通常のルックアップは、テンプレート定義のポイントでのみ実行されます。

したがって、の場合、名前空間に特定のテンプレートがないためstd::string、ジェネリックinit関数テンプレートのみが表示されて呼び出されますstd。の場合A、より具体的な関数はのグローバル名前空間にありAます。

文字列固有の関数がの前に表示されるように前方宣言するとdoSomething、通常の非修飾ルックアップはそれを定義で検出し、後で使用します。

次のように呼び出すinitと、引数に依存するルックアップが禁止されるため、ジェネリックテンプレートも使用されAます。

template <typename T>
void doSomething(T& t){
    (init)(t);
    // won't do ADL
}

(サイドノードとして:その場合、インスタンス化時に引数依存のルックアップが禁止されるだけでなく、initそもそも依存名にはなりません-括弧で囲まれていない、修飾されていない関数名のみが依存になります。したがって、非定義でのADLルックアップはとにかく行われ、インスタンス化でのルックアップは、そこで行われるADLとは異なるフォームがあったとしても、まったく行われません。)

于 2010-07-05T09:41:45.753 に答える