以下程序在两个单独的命名空间 (和)中定义了两个函数模板A::foo<>()
和。这两个函数模板的签名相同,只是分配给它们的第二个模板参数的默认参数不同。最终,它们的名称被相应的一对声明带入了范围: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
}
我希望第二个using
声明在这里会导致编译错误:毕竟,当我尝试在同一个命名空间中定义这两个模板时,我会得到这样的结果。
令我惊讶的是,我尝试过的每个编译器(GCC 4.7.2、GCC 4.8.0 beta、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
}
该程序也可以在上述所有编译器上编译,而我预计第二个using
声明会导致编译器错误。
问题#2:这是正确的吗?这可能是“不需要诊断”的情况吗?鼓励参考 C++11 标准。