I'm writing a class, like std::vector can be construct by n value or iterator [first, last), example code like below:
template<typename T>
class Test1{
public:
Test1(size_t n, const T& v){
data_ = new T[n];
for(size_t i = 0; i < n; n){
data_[i] = v;
}
}
template<typename Iterator>
Test1(Iterator first, Iterator last){
size_t n = std::distance(first, last);
data_ = new T[n];
while(first != last){
*data_ = *first ;
}
}
Test1(){
if(nullptr != data_){
delete[] data_;
data_ = nullptr;
}
}
T* data_;
};
usage:
Test1<int> t1(2, 0);
std::vector<int> vec{1, 2, 3};
Test1<int> t2(vec.begin(), vec.end());
but compile error:
...
In instantiation of Test1<T>::Test1(Iterator, Iterator) [with Iterator = int; T = int]
error: invalid type argument of unary
...
so my question is how to realize the both function, why template can't be compile and how to change it(restrict iterator type)?
CodePudding user response:
The code doesn't compile because t1
is trying to invoke the iterator constructor.
C 20
The simplest way to solve this is simply using the C 20 concept std::input_iterator
, like so:
template<std::input_iterator Iterator>
Test1(Iterator first, Iterator last){
size_t n = std::distance(first, last);
data_ = new T[n];
while(first != last){
*data_ = *first ;
}
}
Additionally you will need to remove the invalid attempt to initialize the pointer (data_(n, v)
) and increment i
instead of n
in the n value constructor.
C 11
First we'll need a little extra utility:
template <typename T, typename = void>
struct is_iterator {
static constexpr bool value = false;
};
template <typename T>
struct is_iterator<T, decltype(*std::declval<T>() , void())> {
static constexpr bool value = true;
};
This custom type trait uses SFINAE to check if the provided type can be incremented and dereferenced (the same way you're doing in your code).
You can use it like this:
template<typename Iterator, typename std::enable_if<is_iterator<Iterator>::value, bool>::type = true>
Test1(Iterator first, Iterator last){
size_t n = std::distance(first, last);
data_ = new T[n];
while(first != last){
*data_ = *first ;
}
}