Do non-dependent default template arguments of fun

2019-03-18 18:36发布

问题:

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

回答1:

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.