Home > database >  Class template argument deduction for class with additional non-type arguments
Class template argument deduction for class with additional non-type arguments

Time:07-03

Is it possible to make CTAD work for T in this case?

enum class boundary_type:int{inclusive, exclusive};

template<class T, boundary_type left, boundary_type right>
struct interval
{
    using value_type = T;

    T begin;
    T end;
};

I tried to add the decuction guide


template<boundary_type left, boundary_type right, class T>
interval(T, T) -> interval<T, left, right>;

But still gets error

wrong number of template arguments (2, should be 3)

when trying

interval<boundary_type::inclusive, boundary_type::exclusive>{0, 2}

CodePudding user response:

CTAD cannot work with the partially explicitly specified template parameter. But you can do this using normal template function

template<boundary_type left, boundary_type right, class T>
auto make_interval(T begin, T end) {
  return interval<T, left, right>{begin, end};
}

int main() {
  auto intval = make_interval<boundary_type::inclusive, 
                              boundary_type::exclusive>(0, 2);
}

CodePudding user response:

With a bit more code you could allow the user to use a similar syntax by providing wrapper types for the boundaries containing information about the boundaries on information provided by those wrappers:

enum class boundary_type :int { inclusive, exclusive };

template<class T>
struct exclusive
{
    static constexpr ::boundary_type boundary_type = ::boundary_type::exclusive;
    using value_type = T;

    explicit exclusive(T bound)
        : m_bound(bound)
    {
    }

    operator T() const
    {
        return m_bound;
    }

    T m_bound;
    
};

template<class T>
struct inclusive
{
    static constexpr boundary_type boundary_type = ::boundary_type::inclusive;
    using value_type = T;

    inclusive(T bound)
        : m_bound(bound)
    {
    }

    operator T() const
    {
        return m_bound;
    }

    T m_bound;
    
};

template<class T, boundary_type left, boundary_type right>
struct interval
{
    using value_type = T;

    T begin;
    T end;
};

template<class Left, class Right>
interval(Left, Right) -> interval<
    std::common_type_t<typename std::remove_cvref_t<Left>::value_type, typename std::remove_cvref_t<Right>::value_type>,
    std::remove_cvref_t<Left>::boundary_type,
    std::remove_cvref_t<Right>::boundary_type
>;

usage

interval intrvl{ inclusive(0), exclusive(2) };
static_assert(std::is_same_v<decltype(intrvl), interval<int, boundary_type::inclusive, boundary_type::exclusive>>);
  • Related