1

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;
}
xerion
  • 303
  • 2
  • 11
  • 1
    And your *specific* question is? – Jesper Juhl Feb 05 '19 at 19:05
  • Why a `#ifdef 1` and not a [mcve] with the corresponding question? – Matthieu Brucher Feb 05 '19 at 19:08
  • @JesperJuhl Updated the question to be more clear which is how to make this work on MSVC since it works fine on both Clang and GCC – xerion Feb 05 '19 at 19:15
  • @MatthieuBrucher The #if 1 is there cause I have already searched stackoverflow and saw that people were already reporting problems with is_detected in MSVC so I decided to test both implementations to make sure that I am not missing anything. Does it really matter ? – xerion Feb 05 '19 at 19:17
  • To be precise, it works with templates, but doesn't work with recursive templates, i.e. the CRTP construction that you have with the call to `has_bar` in `InterfaceImpl`. In all fairness, [expression SFINAE](https://blogs.msdn.microsoft.com/vcblog/2016/06/07/expression-sfinae-improvements-in-vs-2015-update-3/) is not yet fully supported in MSVC ("*improved*" != "*supported*"). – rustyx Feb 05 '19 at 19:42
  • @rustyx Seems like this is the case, making the `NonTemplate` classes template it still works fine. Are there any possible workarounds? – xerion Feb 05 '19 at 20:00

0 Answers0