This is my (stripped) class and instantiation of one object:
template <typename T, typename Allocator = std::allocator<T> >
class Carray {
typedef typename Allocator::size_type size_type;
// ...
explicit Carray(size_type n, const T& value, const Allocator& alloc = Allocator()) {
// ...
}
template<typename InputIterator>
Carray(InputIterator first, InputIterator last, const Allocator& alloc = Allocator()) {
// ...
}
// ...
}
Carray<int> array(5, 10);
I would expect this to call the Carray(size_type, const T&, const Allocator&)
constructor, but it doesn't. Apparantly this resolutes to template<typename InputIterator> Carray(InputIterator, InputIterator, const Allocator&)
.
What should I change to make this work as intended? I find it weird also, because a call to std::vector<int> v(5, 10)
works perfectly fine. And if I look at the definition of the constructors in my GCC's implementation I find this (I renamed some compiler-implementation names, like __n
):
template<typename T, typename A = std::allocator<T> >
class vector {
typedef size_t size_type;
typedef T value_type;
typedef A allocator_type;
// ...
explicit vector(size_type n, const value_type& value = value_type(), const allocator_type& a = allocator_type());
template<typename InputIterator>
vector(InputIterator first, InputIterator last, const allocator_type& a = allocator_type());
// ...
};
which seems to be the same.
This should work with all iterator types (including pointers) and the current standard.
Explanation, an iterator must normally define several types such as
iterator_category
, and you can take advantage of this and sfinae to detect real iterators. Complication is that pointers are also iterators, but don't have these types defined (somethingstd::iterator_traits
provides a specialization for), so the above takes a similar approach, if the passed in type is a pointer, then it is by default treated as an iterator. This approach saves you having to test for integral types.See demo: http://www.ideone.com/E9l1T
Try this. It will eliminate the iterator constructor from consideration if two ints are passed:
Reference: http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html
EDIT: responding to "Is there any way with just the C++03 STL and without boost?"
I don't know if std::type_traits is in C++03 or not -- I always have boost available, so I just use it. But you can try this. It will work in this specific case, but may not have the generality you require:
The first constructor expects the 'value' argument to be passed by reference, while the second constructor expects the first 2 values to be passed by value. In my experience, C++ is quite strict about this distinction, try passing an integer variable instead of an integer value as the 2nd argument to your object constructor.
The explicit constructor expects a size_t and an int. You have provided two ints.
Substituting
int
forInputIterator
makes the template a better match.If you look closer at the standard containers, you will see that they use some template meta-programming to determine if the
InputIterator
could be a real iterator or if it is an integer type. This then redirects to a different construction.Edit
Here is one way of doing it:
You could also use boost::type_traits if the compiler doesn't have std::type_traits.