Reputation: 411
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
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 c++14 I wouldn't bother with the sfinae
alias, but getting rid of the typename
makes it worth it in c++11.
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 c++17 I mean c++20 I mean c++23 Concepts feature of C++.
Upvotes: 1