c ++ ctor模板/公共函数(模板限制迭代器)无法编译

c++ ctor template / common function (template restrict iterator) can't compile

我正在写一个class,比如std::vector可以由n值或迭代器[first, last]构造,示例代码如下:

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_;
};

用法:

Test1<int> t1(2, 0);

std::vector<int> vec{1, 2, 3};
Test1<int> t2(vec.begin(), vec.end());

但是编译错误:

...
In instantiation of Test1<T>::Test1(Iterator, Iterator) [with Iterator = int; T = int]
error: invalid type argument of unary
...

所以我的问题是如何实现这两个功能,为什么模板不能编译以及如何更改它(限制迭代器类型)?

一种不用检查迭代器的方法,也可以解决这个问题:

template<typename Iterator, typename std::enable_if<!std::is_integral<Iterator>::value, int>::type = 0>
Test1(Iterator first, Iterator last){ // integral can't use this function
    cout << "using first last" << endl;
    size_t n = std::distance(first, last);
    data_ = new T[n];
    while(first != last){
        *data_++ = *first++;
    }
}

代码无法编译,因为 t1 正在尝试调用迭代器构造函数。

C++20

解决这个问题的最简单方法就是使用 C++20 概念 std::input_iterator,如下所示:

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++;
    }
}

此外,您需要删除初始化指针 (data_(n, v)) 的无效尝试,并在 n 值构造函数中递增 i 而不是 n

C++11

首先我们需要一些额外的工具:

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;
};

此自定义类型特征使用 SFINAE 检查提供的类型是否可以递增和取消引用(与您在代码中所做的方式相同)。

你可以这样使用它:

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++;
    }
}