std :: is_detected в MSVC не работает с шаблонами - PullRequest
0 голосов
/ 05 февраля 2019

Я реализовал std::experimental::is_detected из обоих https://en.cppreference.com/w/cpp/experimental/is_detected, а также Странное поведение MSVC с std :: эксперимент :: :: is_detected , чтобы быть уверенным, что там ничего не происходит.

Однако из того, что я вижу, is_detected, похоже, не работает для шаблонных классов в MSVC, хотя это нормально как для Clang, так и для GCC.Любые идеи о том, как заставить это работать в MSVC?

Полный код воспроизведения также закончен в 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;
}
...