is it possible to specify templated class in concepts?

Viewed 119

say I have a function that converts string to numeric type as below

template<class T>
T to_t(const std::string& str) {
    return boost::lexical_cast<T>(str);
}

and I want to make the function being able to convert numeric str to std::chrono::duration, so I can write code like to_t<std::chrono::seconds>("1234") to_t<std::chrono::nanoseconds>("1234")

I wanted to implement this using concepts, but can't figure out how to write constraints for types that are std::chrono::duration as this is a class with template parameters.

if concepts is not applicable here, what's the recommended way to implement this function for std::chrono::duration? thanks

2 Answers

Yes, you can create a duration concept.

Either anything with the members of std::duration

template <std::regular T>
concept duration = requires (T a, T b, typename T::rep r) {
    typename T::rep;
    typename T::period;
    { a + b } -> std::same_as<T>;
    { a - b } -> std::same_as<T>;
    { a * r } -> std::same_as<T>;
    { r * a } -> std::same_as<T>;
    { a / r } -> std::same_as<T>;
    { a / b } -> std::same_as<T>;
    { a % r } -> std::same_as<T>;
    { a % b } -> std::same_as<T>;
}

Or specifically if it is an instantiation

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

template <typename Rep, typename Period>
struct is_duration<std::duration<Rep, Period>> : std::true_type {};

template <typename T>
concept duration = is_duration<T>::value

Your concept can be defined as:

template <class Dur>
concept stl_duration = std::same_as<
  Dur, std::chrono::duration<typename Dur::rep, typename Dur::period>
>;

Or more generally, use Barry's Specializes:

template <typename T, template <typename...> class Z>
inline constexpr bool is_specialization_of = false;

template <template <typename...> class Z, class... Args>
inline constexpr bool is_specialization_of<Z<Args...>, Z> = true;

template <typename T, template <typename...> class Z>
concept Specializes = is_specialization_of<T, Z>;

template <class Dur>
concept stl_duration = Specializes<Dur, std::chrono::duration>;

Then your to_t can defined as:

template<stl_duration T>
T to_t(const std::string& str) {
  return boost::lexical_cast<T>(str);
}

Demo.

Related