最小限のプログラム:
#include <stdio.h>
#include <type_traits>
template<typename S, typename T>
int foo(typename T::type s) {
return 1;
}
template<typename S, typename T>
int foo(S s) {
return 2;
}
int main(int argc, char* argv[]) {
int x = 3;
printf("%d\n", foo<int, std::enable_if<true, int>>(x));
return 0;
}
出力:
1
これでコンパイルエラーにならないのはなぜですか? テンプレート コードが生成されると、関数int foo(typename T::type search)
とint foo(S& search)
は同じ署名を持ちませんか?
テンプレート関数のシグネチャを少し変更しても、まだ機能します (上記の例で期待したとおりです)。
template<typename S, typename T>
void foo(typename T::type s) {
printf("a\n");
}
template<typename S, typename T>
void foo(S s) {
printf("b\n");
}
ただし、これはそうではなく、唯一の違いは、一方が int シグネチャを持ち、もう一方が最初のテンプレート パラメーターによって定義されていることです。
template<typename S, typename T>
void foo(typename T::type s) {
printf("a\n");
}
template<typename S, typename T>
void foo(int s) {
printf("b\n");
}
コンパイラ エラー (Clang):
test.cpp:26:2: error: call to 'foo' is ambiguous
foo<std::enable_if<true, int>>(3);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:16:6: note: candidate function [with T = std::__1::enable_if<true, int>]
void foo(typename T::type s) {
^
test.cpp:21:6: note: candidate function [with T = std::__1::enable_if<true, int>]
void foo(int s) {
^
1 error generated.
私が取り組んでいるプロジェクトでこれに似たコードを使用していますが、特定のケースで未定義の動作を引き起こす、私が理解していない言語に微妙にあるのではないかと心配しています。また、Clang と VS11 の両方でコンパイルされることにも言及する必要があるため、単なるコンパイラのバグではないと思います。
編集: 2 番目のケース (タイプミス) を修正しました。Clang からのエラー メッセージを追加しました。
編集#2: T::type の意味を尋ねた人のために。
http://en.cppreference.com/w/cpp/types/enable_ifから:
template< bool B, class T = void > struct enable_if;
B が true の場合、std::enable_if は T と等しい public メンバ typedef 型を持ちます。それ以外の場合、メンバ typedef はありません。
enable_if は構造体です。基本的に、enable_if の最初のテンプレート パラメーターで評価された式が true の場合 (上記の例の場合は true)、type
2 番目のテンプレート パラメーターと同じ型を持つパブリック メンバーが存在します。
の場合enable_if<true, int>
、enable_if::type の型は int です。