BeeOnRope
BeeOnRope

Reputation: 64955

Concept that models only the std::chrono duration types

Can I write a concept that recognizes any of the standard std::chrono duration types without just listing them all explicitly like:

template <typename T>
concept IsStdDuration =
std::same_as<T, std::chrono::nanoseconds> || std::same_as<T, std::chrono::microseconds> || ...

Yes, I know I could use a "any of these types" helper concept to reduce the boilerplate, but I'm wondering if I can avoid listing them all explicitly in the first place.

Upvotes: 1

Views: 821

Answers (4)

Oliver Sch&#246;nrock
Oliver Sch&#246;nrock

Reputation: 1156

Combining approaches, adding cvref compatibility, without repeating code and defining the concept with some tests.

(this does not give you a generically applicable type trait, because remove_cvref is applied at the concept definition level)

template <class T>
struct is_duration_t : std::false_type {};

template <class Rep, class Period>
struct is_duration_t<std::chrono::duration<Rep, Period>> : std::true_type {};

template <typename T>
concept duration = is_duration_t<std::remove_cvref_t<T>>::value;

static_assert(duration<std::chrono::seconds>, "not a duration");
static_assert(duration<const volatile std::chrono::seconds&>, "not a duration");

Upvotes: 0

ecatmur
ecatmur

Reputation: 157374

Without using a helper, you can pattern match a nested lambda call:

template <typename T>
concept IsStdDuration = requires {
    []<class Rep, class Period>(std::type_identity<std::chrono::duration<Rep, Period>>){}(
        std::type_identity<T>());
};

Upvotes: 3

claz78
claz78

Reputation: 54

Extending from the traits approach in a related answer https://stackoverflow.com/a/47086645/6311962, you can define a concept using trait types:

template <class _Tp>
struct is_chrono_duration : std::false_type {};

template <class _Rep, class _Period>
struct is_chrono_duration<std::chrono::duration<_Rep, _Period>> : std::true_type {};

template<typename _Tp>
concept chrono_duration = is_chrono_duration<_Tp>::value;

Upvotes: 1

Howard Hinnant
Howard Hinnant

Reputation: 218920

<chrono> implementations have to do this operation too. They typically do it as traits instead of concepts, but it is easy to implement the trait and then have a concept reference the trait.

Here is the llvm implementation:

template <class _Tp>
struct __is_duration : false_type {};

template <class _Rep, class _Period>
struct __is_duration<duration<_Rep, _Period> > : true_type  {};

template <class _Rep, class _Period>
struct __is_duration<const duration<_Rep, _Period> > : true_type  {};

template <class _Rep, class _Period>
struct __is_duration<volatile duration<_Rep, _Period> > : true_type  {};

template <class _Rep, class _Period>
struct __is_duration<const volatile duration<_Rep, _Period> > : true_type  {};

Your version should not use the __ prefix, which is reserved for the std::implemenation.

Upvotes: 5

Related Questions