C++17 alternative to C++20 "requires" keyword

Viewed 74

C++20 introduced many improvements like requires, concepts, constraints, modules and much more - functionality you really miss in C++17.

How can a scenario having conditional constructors be implemented in C++17, that could look like the following C++20 example (using requires)?

template <typename T> concept has_type = requires { typename T::type; };

template <typename T>
class someClass {
public:
    using data_t = typename std::conditional_t<has_type<T>, T, std::type_identity<T> >::type;

    constexpr someClass(T const& _a, T const& _b) requires std::is_arithmetic_v<T> : a{_a}, b{_b} {}
    constexpr someClass(data_t const& _a, data_t const& _b,) requires has_type<T> : a{_a}, b{_b} {}

private:
    const data_t a, b;
};

One constructor has to be used in case of T is an arithmetic type (int, float, double, ...). Another constructor needs to catch the case of T being a class/struct having a nested type alias (e.g. struct x { using type=float; };).

1 Answers

Using SFINAE

template <typename, typename = std::void_t<>>
struct HasTypeT : std::false_type {};

template <typename T>
struct HasTypeT<T, std::void_t<typename T::type>> : std::true_type {};


template <typename T>
struct type_identity {
    using type = T;
};

template <typename T>
class someClass {
public:
    using data_t = typename std::conditional_t<HasTypeT<T>::value, T, type_identity<T> >::type;

    template <typename U = T, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
    constexpr someClass(T const& _a, T const& _b) : a{_a}, b{_b} {}

    template <typename U = T, typename = std::enable_if_t<HasTypeT<U>::value>>
    constexpr someClass(typename U::type const& _a, typename U::type const& _b) : a{_a}, b{_b} {}

private:
    const data_t a, b;
};

Demo

Related