Michael Carilli
Michael Carilli

Reputation: 411

Automatic type deduction fails with SFINAE+type traits

This minimal compileable sample seems like a pretty standard setup of SFINAE:

#include <type_traits>

struct AType{};

// Helper type-trait templates for AType
template<typename T> struct isAType{ static const bool value = false; };
template<> struct isAType<AType>{ static const bool value = true; };

template<typename T>
void function( typename std::enable_if<isAType<T>::value, T>::type& t 
) {}

int main()
{
  AType a1;

  // This line, using automatic type deduction, fails to compile:  
  // function( a1 );

  // If you manually specify template parameter, it compiles:
  function<AType>( a1 );
}

The error message I get, when function( a1 ); is uncommented, is the following:

main.cpp: In function ‘int main()’:
main.cpp:17:16: error: no matching function for call to ‘function(AType&)’
   function( a1 );
                ^
main.cpp:10:6: note: candidate: template<class T> void function(typename 
std::enable_if<isAType<T>::value, T>::type&)
 void function( typename std::enable_if<isAType<T>::value, T>::type& t ) 
{}
      ^
main.cpp:10:6: note:   template argument deduction/substitution failed:
main.cpp:17:16: note:   couldn't deduce template parameter ‘T’
   function( a1 );

I've seen some posts indicating that "T" is in a nondeduced context. "Nondeduced context" is a new concept to me but enough ink has been spilled elsewhere that I can figure it out. My question here, I guess, is whether my declaration of function can be tweaked in such a way that automatic type deduction will succeed. Is there a canonical way to implement SFINAE with type traits such that automatic type deduction succeeds?

Upvotes: 1

Views: 147

Answers (1)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275510

Not all C++ compilers support it, but if yours does this is the cleanest way to do this:

template<bool b>
using sfinae = typename std::enable_if< b, bool >::type;

template<class T,
  sfinae<isAType<T>::value> =true
>
void function( T& t  )
{
}

in I wouldn't bother with the sfinae alias, but getting rid of the typename makes it worth it in .

Note that the =true portion is required, but if it was =false it would mean the same thing.

What is going on here is we define a non-type template parameter whose type only exists if the test passes. We then give it a default value.

I find this technique reads the most like the incoming I mean I mean Concepts feature of C++.

Upvotes: 1

Related Questions