I implemented std::experimental::is_detected
from both https://en.cppreference.com/w/cpp/experimental/is_detected as well as Strange MSVC behaviour with std::experimental::is_detected to be sure that nothing is going on there.
However from what I see is_detected
does not seem to work for template classes in MSVC while it is fine on both Clang and GCC. Any ideas on how to make this work in MSVC?
The full reproduction code is also over at https://godbolt.org/z/wYe9M3
#include <type_traits>
// Type representing a missing type.
struct nonesuch
{
nonesuch() = delete;
~nonesuch() = delete;
nonesuch(nonesuch const&) = delete;
void operator=(nonesuch const&) = delete;
};
#if 1 // from cppreference
namespace detail {
template <class Default, class AlwaysVoid,
template<class...> class Op, class... Args>
struct detector {
using value_t = std::false_type;
using type = Default;
};
template <class Default, template<class...> class Op, class... Args>
struct detector<Default, std::void_t<Op<Args...>>, Op, Args...> {
// Note that std::void_t is a C++17 feature
using value_t = std::true_type;
using type = Op<Args...>;
};
} // namespace detail
template <template<class...> class Op, class... Args>
using is_detected = typename detail::detector<nonesuch, void, Op, Args...>::value_t;
template <template<class...> class Op, class... Args>
using detected_t = typename detail::detector<nonesuch, void, Op, Args...>::type;
#else
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(std::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)) {};
}
template <template< typename... > class Check, typename... Args>
using is_detected = typename internal::detect<nonesuch, void, Check, Args...>::value_t;
#endif
template <typename T, typename ...Ts>
using foo_bar = decltype(std::declval<T>().bar(std::declval<Ts>()...));
template <typename T>
using has_bar = is_detected<foo_bar, T, int>;
template<class T>
struct InterfaceImpl
{
static constexpr bool val = has_bar<T>::value;
protected:
int bar(int t) const {return 2;}
};
struct S : public InterfaceImpl<S> {};
struct S2 : public InterfaceImpl<S2>
{
int bar(int t) const {return 3;}
};
struct NonTemplate{};
struct NonTemplate2{
int bar(int t) const {return 3;}
};
int main(void)
{
S s;
static_assert(s.val == false);
S2 s2;
static_assert(s2.val == true);
static_assert(has_bar<NonTemplate>::value == false);
static_assert(has_bar<NonTemplate2>::value == true);
return 0;
}