I am implementing a class similar to std::list. I am having problems with the wrong constructor being called.
Here's a working code snippet:
#include <iostream>
template <typename T>
class dslist
{
public :
typedef size_t size_type ;
public :
explicit dslist( const size_type count , const T &value ) ;
template <typename InputIt>
explicit dslist( InputIt first , InputIt last ) ;
} ;
template <typename T>
dslist<T>::dslist( const size_type count , const T &value )
{
std::cout << "count, value ctor" << std::endl ;
}
template <typename T>
template <typename InputIt>
dslist<T>::dslist( InputIt first , InputIt last )
{
std::cout << "Iterator" << std::endl ;
}
int main()
{
dslist<int> l( 10 , 20 ) ;
return 0 ;
}
If I run this, the iterator constructor is called. But, really the first constructor (count, value) should be called.
How to ensure that the first constructor is called in this case?
Edit to add the solution here extracted from the answer:
Solution
#include <iostream>
#include <utility>
#include <vector>
#include <type_traits>
template <typename T>
class dslist
{
public :
typedef size_t size_type ;
public :
explicit dslist( const size_type count , const T &value ) ;
template <typename InputIt, typename = decltype(*std::declval<InputIt>())>
explicit dslist( InputIt first , InputIt last ) ;
} ;
template <typename T>
dslist<T>::dslist( const size_type count , const T &value )
{
std::cout << "count, value ctor" << std::endl ;
}
template <typename T>
template <typename InputIt, typename>
dslist<T>::dslist( InputIt first , InputIt last )
{
std::cout << "Iterator" << std::endl ;
}
int main()
{
dslist<int> l( 10 , 20 ) ;
std::vector<int> v( 10 ) ;
dslist<int> l1( std::begin( v ) , std::end( v ));
return 0 ;
}
Given dslist<int> l( 10 , 20 ) ;
, the template constructor wins in overload resolution because it's an exact match. While the 1st constructor requires an impliclit conversion from int
(the type of 10
) to size_t
(an unsigned integer type).
You can use SFINAE to exclude undesired specializations from the overload set. e.g. the iterator type is supposed to support operator*
.
template <typename InputIt, typename = decltype(*std::declval<InputIt>())>
explicit dslist( InputIt first , InputIt last ) ;