C++ 如何使构造函数接受所有类型的迭代器?

C++ 如何使构造函数接受所有类型的迭代器?,c++,class,templates,iterator,C++,Class,Templates,Iterator,我正在创建一个自定义的Vector/ArrayList类。但是我在创建构造函数的迭代版本时遇到了麻烦。下面的代码可以工作,但问题是当我想像这样创建ArrayList时: arraylistarr(1,5) 编译器不知道函数应该选择哪个版本 我怎样才能解决这个问题 施工人员: ArrayList(const size_type elem_amount, value_type elem) : arr_size { elem_amount }, arr_capacity{ elem_amount }

我正在创建一个自定义的Vector/ArrayList类。但是我在创建构造函数的迭代版本时遇到了麻烦。下面的代码可以工作,但问题是当我想像这样创建ArrayList时:

arraylistarr(1,5)

编译器不知道函数应该选择哪个版本

我怎样才能解决这个问题

施工人员:

ArrayList(const size_type elem_amount, value_type elem) : arr_size { elem_amount }, arr_capacity{ elem_amount }
{
    array = std::uninitialized_fill_n(allocator.allocate(arr_size), arr_size, elem) - arr_size;
    first = array;
    last = array + arr_size - 1;
}


template<typename ITER>
ArrayList(ITER begin, ITER end) : arr_size{ static_cast<size_type>(end - begin) }, arr_capacity{ arr_size }
{
    std::uninitialized_copy(begin, end, array = allocator.allocate(arr_size));
    first = array;
    last = array + arr_size - 1;
}

ArrayList(const size\u type elem\u amount,value\u type elem):arr\u size{elem\u amount},arr\u capacity{elem\u amount}
{
array=std::未初始化的数组填充(allocator.allocate(arr\u size),arr\u size,elem)-arr\u size;
第一个=数组;
last=阵列+阵列大小-1;
}
模板
ArrayList(ITER-begin,ITER-end):arr\u大小{static\u cast(end-begin)},arr\u容量{arr\u大小}
{
std::未初始化的_拷贝(开始、结束、数组=分配器。分配(arr_大小));
第一个=数组;
last=阵列+阵列大小-1;
}

您需要做的是将模板约束为仅当模板类型被推断为迭代器类型时才起作用。由于您要初始化
size
这意味着您希望迭代器是随机访问的。我们可以使用iterator_category
来检查这一点

template<typename ITER, 
         std::enable_if_t<std::is_base_of_v<typename std::iterator_traits<ITER>::iterator_category, 
                                            std::random_access_iterator_tag>, bool> = true>
ArrayList(ITER begin, ITER end) : arr_size{ static_cast<size_type>(end - begin) }, arr_capacity{ arr_size }
{
    std::uninitialized_copy(begin, end, array = allocator.allocate(arr_size));
    first = array;
    last = array + arr_size - 1;
}
模板
ArrayList(ITER-begin,ITER-end):arr\u大小{static\u cast(end-begin)},arr\u容量{arr\u大小}
{
std::未初始化的_拷贝(开始、结束、数组=分配器。分配(arr_大小));
第一个=数组;
last=阵列+阵列大小-1;
}
使用C++20,您可以使用概念 请注意,一些编译器开始支持C++20的新功能,包括以下概念:

因此,为了区分两个构造函数,使用C++20可以使用概念类型限制允许的模板参数:

template<std::random_access_iterator ITER>
         // see comment by Nathan Oliver for using random_access_iterator 
ArrayList(ITER begin, ITER end)
: arr_size{ static_cast<size_type>(end - begin) }, arr_capacity{ arr_size }
{
    std::uninitialized_copy(begin, end, array = allocator.allocate(arr_size));
    first = array;
    last = array + arr_size - 1;
}
模板
//请参阅Nathan Oliver关于使用随机访问迭代器的评论
ArrayList(ITER开始,ITER结束)
:arr_size{static_cast(end-begin)},arr_容量{arr_size}
{
std::未初始化的_拷贝(开始、结束、数组=分配器。分配(arr_大小));
第一个=数组;
last=阵列+阵列大小-1;
}
如果您希望定义自己的概念(本例中无需定义,只是为了练习),可以为迭代器定义一个概念:

template<typename ITER>
concept Iterator = requires {
    typename std::iterator_traits<ITER>::iterator_category;
};
模板
概念迭代器=需要{
typename std::iterator_traits::iterator_category;
};
或者,在本例中使用RandomAccessIterator:

template<typename ITER>
concept Iterator = requires {
    typename std::iterator_traits<ITER>::iterator_category;
};
template<typename ITER>
concept RandomAccessIterator = std::is_base_of_v <
    std::random_access_iterator_tag,
    typename std::iterator_traits<ITER>::iterator_category
>;
模板
concept RandomAccessIterator=std::是_v的_base_吗<
std::随机访问迭代器标记,
类型名称std::迭代器特征::迭代器类别
>;
并使用与上述相同的方法,例如:

template<RandomAccessIterator ITER>
ArrayList(ITER begin, ITER end)  // ...
模板
阵列列表(ITER开始,ITER结束)/。。。
代码:


(请注意,这应该是范围的一部分,但可以如上所述自行实现)。

我将使用
std::is_base_of_v
(参数顺序颠倒)而不是
is_v
。这使得更改为不太特定的类型变得更容易,并且将来会根据C++20
std::continuous\u iterator\u tag
@aschepler Good call对代码进行验证。我只是在想这个。在中编辑。请注意,
input\u iterator
对于契约来说太弱了。执行
arr\u size{static\u cast(end-begin)}
至少需要随机访问迭代器。@NathanOliver-确实如此。固定的。