With "non-dependent" here I mean "non-dependent on any other template arguments of that specific function template".
While answering this question, I thought I found the answer, but according to @Johannes (in the comments to my answer), I'm misinterpreting the standard here. Take the following simple example:
#include <type_traits>
template<class T>
struct X{
template<class U = typename T::type>
static void foo(int){}
static void foo(...){}
};
int main(){
X<std::enable_if<false>>::foo(0);
}
(Live version.)
Is there any guarantee that the above compiles? GCC and Clang disagree here, as can be seen in the live version when switching between them. Interestingly, though, the following is accepted by GCC:
#include <type_traits>
template<class T>
struct X{
template<bool = T::f()>
static void foo(int){}
static void foo(...){}
};
struct Y{
static bool f(){ return true; }
};
int main(){
X<Y>::foo(0);
}
(Live version.)
The second snippet will only print foo(int)
if T
contains a constexpr
static function f
. Again, interestingly, if you completely remove f
from Y
(or pass, say, int
instead), GCC complains about a missing member, indicating that it doesn't allow for SFINAE - which is contradictory with the previous observation. Clang takes all variations and applies SFINAE, and I wonder if that's what is guaranteed by the standard.
(FWIW, MSVC with the Nov CTP generally agrees with Clang, but crashes on the second snippet if the function is present, likely because they don't have constexpr
. I submitted a bug report here.)