Reputation: 64955
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
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
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
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
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