Detect.h
// Detect.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2022
#pragma once
#ifndef Ceda_cxUtils_Detect_H
#define Ceda_cxUtils_Detect_H
#include <type_traits>
// See https://people.eecs.berkeley.edu/~brock/blog/detection_idiom.php
// https://en.cppreference.com/w/cpp/experimental/is_detected
// https://stackoverflow.com/questions/66078754/c17-how-to-test-class-has-a-member-variable
namespace ceda
{
// This is from a proposal for C++, made redundant by C++20 requires
/*
template <typename...>
using void_t = void;
// Primary template handles all types not supporting the operation.
template <typename, template <typename> class, typename = void_t<>>
struct detect : std::false_type {};
// Specialization recognizes/validates only types supporting the archetype.
template <typename T, template <typename> class Op>
struct detect<T, Op, void_t<Op<T>>> : std::true_type {};
*/
struct nonesuch
{
~nonesuch() = delete;
nonesuch(nonesuch const&) = delete;
void operator=(nonesuch const&) = delete;
};
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...>
{
using value_t = std::true_type;
using type = Op<Args...>;
};
}
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;
template <class Default, template<class...> class Op, class... Args>
using detected_or = detail::detector<Default, void, Op, Args...>;
// test for existence of static_cast<To>(From)
template <typename To, typename From> using has_static_cast_t = decltype(static_cast<To>(std::declval<From>()));
template <typename To, typename From> using has_static_cast = is_detected<has_static_cast_t, To, From>;
// implement implicit_cast<T>(x)
namespace detail
{
template<class T> struct icast_identity { using type = T; };
}
template <typename T>
inline T implicit_cast (typename detail::icast_identity<T>::type x)
{
return x;
}
// test for existence of implicit_cast<To>(From)
template <typename To, typename From> using has_implicit_cast_t = decltype(implicit_cast<To>(std::declval<From>()));
template <typename To, typename From> using has_implicit_cast = is_detected<has_implicit_cast_t, To, From>;
// test for existence of T1==T2
template <typename T1, typename T2> using compareEqual_t = decltype(std::declval<T1 const &>() == std::declval<T2 const &>());
//template <typename T1, typename T2 = T1> using has_compare_equal = is_detected<compareEqual_t, T1, T2>;
template <typename T1, typename T2 = T1>
struct has_compare_equal
{
constexpr static bool value = is_detected<compareEqual_t, T1, T2>::value;
};
// test for existence of T1<T2
template <typename T1, typename T2> using compareLess_t = decltype(std::declval<T1 const &>() < std::declval<T2 const &>());
//template <typename T1, typename T2 = T1> using has_compare_less = is_detected<compareLess_t, T1, T2>;
template <typename T1, typename T2 = T1>
struct has_compare_less
{
constexpr static bool value = is_detected<compareLess_t, T1, T2>::value;
};
}
#endif // include guard