Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do non-dependent default template arguments of function templates allow for SFINAE?

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

like image 866
Xeo Avatar asked Mar 06 '13 13:03

Xeo


People also ask

Which of the following types Cannot be used for a non type template parameter?

Non-type template parameters are one of the few places in C++ where a visible distinction is made between class types and others: integral types, enum types, pointer types, point- to-member types, reference types and std::nullptr_t can all be used as non-type template parameters, but class types cannot.

Can template parameters have default values?

Template parameters may have default arguments.

What are template arguments enlist types of template arguments?

A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)

What can the template parameter in C++ template definition be?

A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.


1 Answers

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.

like image 197
Johannes Schaub - litb Avatar answered Oct 21 '22 15:10

Johannes Schaub - litb