Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Two identical constructors however compiler selects the templated one

I am trying to implement a list container in C++, and I have problem with compiler selecting the wrong constructor overload.

The constructors are as follows:

list(size_type count, const T& value);

template<typename InputIt>
list(InputIt begin, InputIt end);

When I initialize the object in the source file, I can not prevent the compiler from selecting the second overload:

list<int> x(5, 45);

The second overload should be selected when the given arguments are iterators. However, I can't accomplish it.


EDIT: The class declaration looks like this:

template<typename T, typename Allocator = std::allocator<T>> 
class list 
{
public:
    using value_type = T;
    using pointer = T*;
    using const_pointer = const T*;
    using reference = T&;
    using const_reference = const T&;
    using move_reference = T&&; // custom
    using size_type = std::size_t;
    using difference_type = std::ptrdiff_t;

    list(size_type count, const T& value);

    template<typename InputIt>
    list(InputIt begin, InputIt end);
    // ...
};
like image 670
Emre Erdog Avatar asked Dec 07 '25 07:12

Emre Erdog


2 Answers

The second overload should be selected when the given arguments are iterable however I can't accomplish it?

You need to SFINAE ("Substitution Failure Is Not An Error") one of the constructors (prior to C++20), so that correct constructors will be chosen.

// Constructor for iterator range
template<typename InputIt
    , std::enable_if_t<
           std::is_constructible_v<
               T, typename std::iterator_traits<InputIt>::value_type>>* = nullptr
           >
    list(InputIt begin, InputIt end)
    /* : contr init list */
{}

See live demo


In C++20, however, just constrain the constructor for std::input_or_output_iterator:

template<typename InputIt>
    requires (std::input_or_output_iterator<InputIt>)
list(InputIt begin, InputIt end) 
  /* : contr init list */
{}

See live demo

like image 175
JeJo Avatar answered Dec 09 '25 01:12

JeJo


The problem is that the templated ctor is a better match because it is an exact match for both the passed arguments 5 and 45 while the non-templated ctor requires a conversion from int (signed int) to size_type (unsigned long) for the first argument 5.

There are multiple way of solving this as shown in the other answer. In particular, with c++20 you can use std::input_or_output_iterator on the templated ctor to constrain it.

like image 26
Anoop Rana Avatar answered Dec 08 '25 23:12

Anoop Rana



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!