redspah redspah - 22 days ago 5
C++ Question

MSVC - Member detection with void_t doesn't work properly

I've run into this the other day.

#include <iostream>
#include <type_traits>
using namespace std;

template<typename... Ts> struct make_void { typedef void type; };
template<typename... Ts> using void_t = typename make_void<Ts...>::type;

template <class, class = void>
struct is_func_chrend_ : std::false_type {};

template <class T>
struct is_func_chrend_<T, ::void_t<decltype(std::declval<T>().NextTile())>> : std::true_type {};

template <class = void, class = void>
struct is_addable : std::false_type {};

template <class T>
struct is_addable<T, ::void_t<decltype(std::declval<T>() + std::declval<T>())>> : std::true_type {};

int main() {
cout << is_addable<int>::value << endl;
return 0;
}


Displays 0 when compiled in MSVC, 1 if compiled in clang or gcc.
Completely removing
is_func_chrend_
makes
is_addable
work properly again.

Makeshift
void_t
used for only C++11-compliant compilers.

Answer

MSVC has yet to ship a C++11 compliant compiler.

Their biggest remaining problem is decltype being used in a SFINAE context.

They improve the situation regularly, making more and more decltype cases work, but it is not reliable.

The way in which it is broken often generates false positives and false negatives when things go wrong, and the failures are non-local in that how you previously used the SFINAE expression can change how it succeeds or fails next time.

You simply cannot safely use decltype based SFINAE in MSVC, unless you carefully decode what your specific version of MSVC can handle, and never leave those bounds. I personally find their descriptions of what works and what doesn't insufficiently clear to feel I can relyably use it.