c++ type tests which are not in the std library.

Some c++ type tests which i found useful:

  • is_range
  • IsStreamInsertable
  • is_callable
  • is_searchable
  • is_vector
  • is_container

Checks if std::begin or std::end can be applied to T.

struct not_this_one {}; // Tag type for detecting which begin/ end are being selected

// Import begin/ end from std here so they are considered alongside the fallback (...) overloads in this namespace
using std::begin;
using std::end;

not_this_one begin( ... );
not_this_one end( ... );

template <typename T>
struct is_range {
    static const bool value =
        !std::is_same<decltype(begin(std::declval<T>())), not_this_one>::value &&
        !std::is_same<decltype(end(std::declval<T>())), not_this_one>::value;
};

#if defined(_MANAGED) // Managed types are never ranges
    template <typename T>
    struct is_range<T^> {
        static const bool value = false;
    };
#endif

template <typename T, typename = void>
struct StringMaker {
    ...
}

template<typename R>
struct StringMaker<R, typename std::enable_if<is_range<R>::value
                     && !::Catch::Detail::IsStreamInsertable<R>::value
                >::type> {
}

Checks if a operator<< is available for T.

template<typename T>
class IsStreamInsertable {
    template<typename SS, typename TT>
    static auto test(int)
        -> decltype(std::declval<SS&>() << std::declval<TT>(), std::true_type());

    template<typename, typename>
    static auto test(...)->std::false_type;

public:
    static const bool value = decltype(test<std::ostream, const T&>(0))::value;
};

Checks if T can be called.

template<typename T>
struct is_callable_impl {
private:
    typedef char(&yes)[1];
    typedef char(&no)[2];

    struct Fallback { void operator()(); };
    struct Derived : T, Fallback { };

    template<typename U, U> struct Check;

    template<typename>
    static yes test(...);

    template<typename C>
    static no test(Check<void (Fallback::*)(), &C::operator()>*);

public:
    static const bool value = sizeof(test<Derived>(0)) == sizeof(yes);
};
template<typename T>
struct is_callable
    : std::conditional<
        std::is_class<T>::value,
        is_callable_impl<T>,
        std::false_type
    >::type
{ };
template<typename T> constexpr bool is_callable_v = is_callable<T>::value;

This checks if T has a member type key_type.

template<class T, class R = void>  
struct enable_if_type { typedef R type; };

template<class T, class Enable = void>
struct is_searchable : std::false_type {};
template<class T>
struct is_searchable<T, typename enable_if_type<typename T::key_type>::type> : std::true_type
{};
template<typename T> constexpr bool is_searchable_v = is_searchable<T>::value;

template <typename T> struct is_vector { static const bool value = false; };

template <class T, class A> struct is_vector<std::vector<T, A>> { static bool const value = true; };

template<typename T>
struct is_container : std::false_type {};

template<typename T>
struct is_container<std::vector<T> > : std::true_type {};
template<typename T>
struct is_container<std::basic_string<T> > : std::true_type {};
template<typename T, int N>
struct is_container<std::array<T,N> > : std::true_type {};