I implemented std::experimental::is_detected
based on this article on cppreference.com (Part of the code is below + working repro).
It works well on G++
Here's a workaround that appears to work with recent MSVC (tested with Visual C++ 19.00.23720.0):
#include <type_traits>
template <typename...>
using void_t = void;
namespace internal
{
template <typename V, typename D>
struct detect_impl
{
using value_t = V;
using type = D;
};
template <typename D, template <typename...> class Check, typename... Args>
auto detect_check(char)
-> detect_impl<std::false_type, D>;
template <typename D, template <typename...> class Check, typename... Args>
auto detect_check(int)
-> decltype(void_t<Check<Args...>>(),
detect_impl<std::true_type, Check<Args...>>{});
template <typename D, typename Void, template <typename...> class Check, typename... Args>
struct detect : decltype(detect_check<D, Check, Args...>(0)) {};
}
struct nonesuch
{
nonesuch() = delete;
~nonesuch() = delete;
nonesuch(nonesuch const&) = delete;
void operator=(nonesuch const&) = delete;
};
template <template< typename... > class Check, typename... Args>
using is_detected = typename internal::detect<nonesuch, void, Check, Args...>::value_t;
(The dummy void
parameter is unused now, it's there just to keep the rest of the implementation intact.)
You need a C++11 compiler to compile the above code, and MSVC 2015 is not a C++11 compiler.
The particular deficit in C++11 compliance you are running into is called "expression SFINAE" by microsoft. Keep an eye out for it being fixed.
Basically, decltype
cannot be used for SFINAE. In laymans terms, SFINAE is the technique you are using for selecting overloads of template functions or classes.
There is usually no workaround.