C++と色々

主にC++やプログラムに関する記事を投稿します。

C++の関数のオーバーロード解決について

問題です。以下のコードで、(a)、(b)、(c)、どの関数が呼ばれるでしょうか。

#include <iostream>
using std::cout;

// (a)
template <typename T>
void f(T) {
    cout << "f(T)";
}

// (b)
template <>
void f(int*) {
    cout << "f(int*)";
}

// (c)
template <typename T>
void f(T*) {
    cout << "f(T*)";
}

int main() {
    int* p;
    f(p);
}

 正解は(c)です。C++では関数のオーバーロードの解決が行われた後、もしオーバーロードの解決で関数テンプレートが選ばれた場合、その関数テンプレートの中でどの特殊化(またはプライマリーテンプレート)が最もマッチするのか考慮されます。
 また、関数テンプレートには部分特殊化は存在しないため、(c)は(a)の部分特殊化ではなく、(a)とは別のプライマリー関数テンプレートという扱いになります。つまり(a)と(c)はオーバーロードの関係となります。(a)のTよりも(c)のT*の方がint*によりマッチしていると判断されるため、(c)が選ばれました。
 もし、(a)と(c)のオーバーロードの解決で、(a)の方がよりマッチされると判断されるような型Tが選ばれた場合*1、プライマリー関数テンプレート(a)とその特殊化(今回は(b))の中で、Tに最もマッチしているものが選ばれます。

*1:例えばintなど