質問: nullptr> void check(T value) { std::cout << "2" << std::endl; } ```
回答: こんにちは。 既に解決していますが、ちょっとだけ補足です。 > > インスタンス化前のシグニチャが異なる型であれば、それらの関数は異なるシグニチャとみなされるからオーバーロードできると本には記述されている > > > 「インスタンス化前のシグニチャ」が何を指すのか分からないと思いませんか? インスタンス化前のものはテンプレートを指していると思いますがテンプレートにシグニチャがあるとは聞いたことはないです。正直どのようなものか想像することも難しいように感じます。(雰囲気はなんとなくわかりますが、このケースでは雰囲気では足りないと思います。) さて、このような文脈でシグニチャといえば、通常は関数のシグニチャを指します。実体化した関数テンプレートはほぼ通常の関数と同じものですので、「実体化後のシグニチャ」は理解できます。 実引数を与えて型推論してインスタンス化を試みることで関数のシグニチャを確定できます。それらのシグニチャ群から適切なものを選択すると理解した方が分かりやすいと思います。(「実体化前のシグニチャ」などという曖昧な概念を導入しないので。) 【補足の補足】 ところで、上記の過程で特定のインスタンス化がエラーになる場合、コンパイル・エラーになるのではなく、オーバーロード解決の候補から外されるというのがSFINAEです。 そして、これは通常関数同士のオーバーロード解決と同じと思います。SFINAEはテンプレート特有であるかのように説明されることが多いですが、そのため却って分かりにくくなっている気がします。 通常関数のオーバーロードを解決する際も採用されないオーバーロード関数の中には当該実引数を渡すとエラーになるものもありますね。それは単にオーバーロードの候補から外されるだけです。 ``` #include void foo(int) { std::cout << "foo(int)\n"; } // これがないとエラーになる。至極、当たり前。 void foo(int*) { std::cout << "foo(int*)\n"; } int main() { foo(123); } ``` wandbox 関数テンプレートのオーバーロード解決で難しい部分は、型推論とオーバーロード解決の優先順位の定義が超複雑なことです。とても覚えることはできないので、規格の狙いを把握して細かい部分はコンパイラに任せるしかないと思います。 【補足の補足の補足】 ちなみに、クラス・テンプレートの部分的特殊化や明示的特殊化も同じ名前で異なるものを定義するオーバーロードの一種です。(そのように呼んでいる人をほとんど見かけないですが。) SFINAEはクラス・テンプレートを実体化する際にも適用されます。 当該実テンプレート引数を与えるとエラーになる部分特殊化や明示的特殊化はオーバーロードの候補から外されます。(クラスには関数のような実引数がないのでちょっと違いますが、狙いは同じと思います。) クラス・テンプレートの実体化に型推論や優先順位は(C++14以前は)なかったので、関数テンプレートのような複雑さはないです。その分不便でした。 C++17でクラス・テンプレートにも型推論を適用できるようになり、便利になりました。その分、複雑になったようです。