redspah redspah - 11 months ago 41
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
work properly again.

used for only C++11-compliant compilers.

Answer Source

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.