My SFINAE code using std::enable_if
compiles in GCC & Clang, but not in MSVC 2013.
The code (also available on cpp.sh) is
#include <iostream>
#include <type_traits>
template <typename T, typename ... AdditionalInputs>
typename std::enable_if<sizeof...(AdditionalInputs) == 0, void>::type
CallDoDataProcessing(T var) {
std::cout << sizeof...(AdditionalInputs) << " additional inputs" << std::endl;
}
template <typename T, typename ... AdditionalInputs>
typename std::enable_if<sizeof...(AdditionalInputs) == 1, void>::type
CallDoDataProcessing(T var) {
std::cout << sizeof...(AdditionalInputs) << " additional inputs" << std::endl;
}
int main() {
CallDoDataProcessing<int>(3);
CallDoDataProcessing<int, int>(3);
return 0;
}
In GCC/Clang, this works perfectly, in MSVC though, I get:
Error 1 error C2039: 'type' : is not a member of 'std::enable_if<false,void>' c:\Users\mrussell\documents\visual studio 2013\Projects\ConsoleApplication1\ConsoleApplication1\ConsoleApplication1.cpp 5 1 ConsoleApplication1
The compiled and run output should be:
0 additional inputs
1 additional inputs
I've seen some similar issues on SO, but none had a clear answer or were slightly tangental.
Reading the MSVC enable_if page, this should work...
How can I use SFINAE in MSVC2013?
UPDATE
Just as a note, this does work in the positive case. For instance, if I comment out the first function, and the call to it, then the rest compiles. i.e. the enable_if<true, void>
on CallDoDataProcessing
does have a type
member.
However, commenting out the second function and call to it (so, leaving the version where sizeof...(AdditionalInputs) == 0
does not work though. Same error.
This suggests that the sizeof...(AdditionalInputs) == 0
call is not being matched, but I can't figure out why it wouldn't be.
Try tag dispatching.
template<std::size_t>
struct size {};
namespace details {
template <typename T, typename ... AdditionalInputs>
void CallDoDataProcessing(T var, size<0>) {
std::cout << sizeof...(AdditionalInputs) << ", aka 0, additional inputs" << std::endl;
}
template <typename T, typename ... AdditionalInputs, std::size_t N>
void CallDoDataProcessing(T var, size<N>) {
std::cout << sizeof...(AdditionalInputs) << " additional inputs" << std::endl;
}
}
template <typename T, typename ... AdditionalInputs>
void CallDoDataProcessing(T var) {
details::CallDoDataProcessing<T, AdditionalInputs>( var, size<sizeof...(AdditionalInputs)>{} );
}
SFINAE is really badly supported by MSVC. Your code looks like valid SFINAE. The fact that MSVC fails to do the right thing is not surprising.
MSVC works much much better with tag dispatching in my experience, and I find it even results in easier to understand code and even error messages sometimes.
What it does not permit is noticing "no, you cannot do this" before the body of the calling function, to make the calling function also state "no, I cannot be done".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With