11

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.)

Community
  • 1
  • 1
Xeo
  • 129,499
  • 52
  • 291
  • 397

1 Answers1

3

I think the code in question is incorrect, as when the class template is instantiated, all member declarations are instantiated, except the definition parts and default arguments of the member functions and member function templates. The Standard also defines when the function default arguments are instantiated precisely.

So default template-arguments are immediately instantiated. The possibility that default arguments could be intended to include default template arguments at this point is very small here in my opinion, because there is no description of when such an argument would be instantiated later.

This is in line with the requirement that "A default template-argument shall not be specified in the template-parameter-lists of the definition of a member of a class template that appears outside of the member's class.", since there would be no way that such a template argument be instantiated immediately when instantiating the surrounding class template.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • If "default template-arguments" are included in "default arguments", then they're also included for the point-of-instantiation explanation, which says it is at the point-of-instantiation of its function template. However, I'm mainly wondering because Clang just accepts all snippets "as expected". – Xeo Mar 06 '13 at 22:54
  • @Xeo but that's extremely unlikely, because it only talks about function calls. A default template argument can be used not only in function calls, but also in the uses of class template instances of any flavour (in fact, the only case for C++03) and explicit specialization and instantiation of function templates. All that is not mentioned anywhere in either the rules about implicit instantiation nor the rules about the point of instantiation. I recommend to open a Clang PR. – Johannes Schaub - litb Mar 06 '13 at 23:36
  • @Xeo Also, a function default template-argument may be used without a function instantiation. Something like `decltype( &X::template foo<> )` could return it but the function would not be ODR-used. Asking for SFINAE in that context would imply overload resolution that otherwise isn't happening. – Potatoswatter Jul 03 '13 at 07:58