/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2020, Danny Robson */ #pragma once #include "concepts/named.hpp" #include #include namespace cruft::concepts { /// Tests if the type has all typedefs required for use with /// std::iterator_traits. template concept supports_iterator_traits = requires { typename T::difference_type; typename T::value_type; typename T::reference; typename T::iterator_category; // C++20 defines `pointer` as void if it's not present. #if __cplusplus <= 201703L typename T::pointer; #endif }; template < typename ContainerT, typename IndexT = std::size_t > concept supports_indexing = requires (ContainerT &t, IndexT idx) { { t[idx] }; }; /// A type that supports arithmetic operators. template concept numeric = requires (T t) { { t * t } -> std::convertible_to; { t / t } -> std::convertible_to; { t - t } -> std::convertible_to; { t + t } -> std::convertible_to; }; /// Anything that can be looped over using begin/end /// /// We don't check end against legacy_iterator because that won't work for std::default_sentinel. /// Rather, the important part is that it's equality comparable against whatever std::begin returns. template concept iterable = requires (T t) { { std::begin (t) } -> named::legacy_iterator; std::begin (t) == std::end (t); std::begin (t) != std::end (t); { std::cbegin (t) } -> named::legacy_iterator; std::cbegin (t) == std::cend (t); std::cbegin (t) != std::cend (t); }; /// A class that supports tuple manipulators. template concept tuple = requires (T a, T b) { // We should be checking this, but it fails for zero length tuples and // it's kind of a low priority right now. // { std::tuple_element<0,T> {} }; { std::tuple_size::value } -> std::convertible_to; { std::tuple_cat (a, b) }; }; }