次のプログラムは、2 つの別個の名前空間 (および) で 2つの関数テンプレートA::foo<>()
および を定義します。2 つの関数テンプレートは署名が同じで、2 番目のテンプレート パラメーターに割り当てられた既定の引数のみが異なります。最終的に、それらの名前は、対応する宣言のペアによってのスコープに取り込まれます。B::foo<>()
A
B
main()
using
#include <type_traits>
namespace A
{
template<
typename T,
typename = typename std::enable_if<
std::is_same<T, int>::value // Let this be condition C
>::type
>
void foo(T) { }
}
namespace B
{
template<
typename T,
typename = typename std::enable_if<
!std::is_same<T, int>::value // This is the negation of C
>::type
>
void foo(T) { }
}
int main() {
using A::foo;
using B::foo; // COMPILES: Is this legal?
foo(42); // Invokes A::foo(), non-ambiguous because of SFINAE
}
ここでは、2 番目の宣言によってコンパイル エラーが発生すると予想using
されます。結局のところ、同じ名前空間でこれら 2 つのテンプレートを定義しようとすると、エラーが発生します。
驚いたことに、これを試したすべてのコンパイラ (GCC 4.7.2、GCC 4.8.0 ベータ、ICC 13.0.1、Clang 3.2) は、プログラムをコンパイルし、A::foo()
.
質問 #1: これは正しいですか? おそらく「診断不要」のケースでしょうか?C++11 標準への参照が推奨されます。
上記のプログラムのこのバリエーションを考えてみましょう。これは基本的に、名前空間ではなくクラスを使用して同じ効果を実現します。
#include <type_traits>
struct X
{
template<
typename T,
typename = typename std::enable_if<
std::is_same<T, int>::value // Here is condition C again
>::type
>
static void foo(T) { }
};
struct Y
{
template<
typename T,
typename = typename std::enable_if<
!std::is_same<T, int>::value // And the negation of C again
>::type
>
static void foo(T) { }
};
struct Z : X, Y
{
using X::foo;
using Y::foo; // COMPILES: Is this legal?
};
int main() {
Z::foo(42); // Invokes X::foo(), non-ambiguous because of SFINAE
}
このプログラムも上記のすべてのコンパイラでコンパイルされますが、2 番目のusing
宣言によってコンパイラ エラーが発生すると予想されます。
質問 #2: これは正しいですか? おそらく「診断不要」のケースでしょうか?C++11 標準への参照が推奨されます。