【问题标题】:Own vector assign implementation自己的向量分配实现
【发布时间】:2020-09-05 09:41:14
【问题描述】:

我正在通过编写所有默认函数来实现类似矢量的 stl。还有一个问题,我不明白为什么它为简单类型调用 ragne 版本的 assign 并且不默认。 下面是实现代码: 向量.h

void assign(size_t count, const T& value){ // Default version
                void assign(size_t count, const T& value){
                if(this->_size < count){
                   this->allocator.deallocate(this->arr, this->_capacity);
                   this->arr = this->allocator.allocate(count);

                   this->_capacity = count;
                }
                for(size_t i = 0; i < count; ++i)
                    this->arr[i] = value;

               this->_size = count;
            }

template<class InputIt>
            void assign(InputIt first, InputIt last){ // Range version
                size_t count = std::distance(first,last);
                if(this->_size < count){
                   this->allocator.deallocate(this->arr, this->_capacity);
                   this->arr = this->allocator.allocate(count);

                   this->_capacity = count;
                }
                for(size_t i = 0; first != last; i++)
                    this->arr[i] = *first++;

                this->_size = count;
            }

主要代码:

 Vector<int> vec;
 vec.assign(5,10);

输出:


/MyVector/MyVector.h: In instantiation of ‘void Vector<T, Allocator>::assign(InputIt, InputIt) [with InputIt = int; T = int; Allocator = std::allocator]’:
../MyVector/main.cpp:52:24:   required from here
../MyVector/MyVector.h:99:45: error: no matching function for call to ‘distance(int&, int&)’
                 size_t count = std::distance(first,last);
                                ~~~~~~~~~~~~~^~~~~~~~~~~~
In file included from /usr/include/c++/7/bits/stl_algobase.h:66:0,
                 from /usr/include/c++/7/bits/char_traits.h:39,
                 from /usr/include/c++/7/ios:40,
                 from /usr/include/c++/7/ostream:38,
                 from /usr/include/c++/7/iostream:39,
                 from ../MyVector/main.cpp:1:
/usr/include/c++/7/bits/stl_iterator_base_funcs.h:138:5: note: candidate: template<class _InputIterator> constexpr typename std::iterator_traits<_Iterator>::difference_type std::distance(_InputIterator, _InputIterator)
     distance(_InputIterator __first, _InputIterator __last)
     ^~~~~~~~
/usr/include/c++/7/bits/stl_iterator_base_funcs.h:138:5: note:   template argument deduction/substitution failed:
/usr/include/c++/7/bits/stl_iterator_base_funcs.h: In substitution of ‘template<class _InputIterator> constexpr typename std::iterator_traits<_Iterator>::difference_type std::distance(_InputIterator, _InputIterator) [with _InputIterator = int]’:
../MyVector/MyVector.h:99:45:   required from ‘void Vector<T, Allocator>::assign(InputIt, InputIt) [with InputIt = int; T = int; Allocator = std::allocator]’
../MyVector/main.cpp:52:24:   required from here
/usr/include/c++/7/bits/stl_iterator_base_funcs.h:138:5: error: no type named ‘difference_type’ in ‘struct std::iterator_traits<int>’
In file included from ../MyVector/main.cpp:2:0:
../MyVector/MyVector.h: In instantiation of ‘void Vector<T, Allocator>::assign(InputIt, InputIt) [with InputIt = int; T = int; Allocator = std::allocator]’:
../MyVector/main.cpp:52:24:   required from here
../MyVector/MyVector.h:107:36: error: invalid type argument of unary ‘*’ (have ‘int’)
                     this->arr[i] = *first++;
                                    ^~~~~~~~
Makefile:725: recipe for target 'main.o' failed
make: *** [main.o] Error 1

我正在使用 C++17

【问题讨论】:

  • 请参阅std::vector::assign() 上的 cppreference。第二个重载特别提到当向量包含整数类型时,做了某些事情来避免选择这个重载。将选择模板重载而不是您自己的(如果向量类型是整数类型)。您需要提供一个处理它的实现。在 C++11 中,这是使用 SFINAE 完成的,但是我在模板方面的能力不足以回答您的问题,抱歉。
  • 为什么要调用“默认”版本? int 不是 size_t,所以模板化的版本是更好的匹配。只需尝试void f(size_t, const int&amp;); template &lt;typename T&gt; void f(T, T);,然后拨打f(1, 2);。它将调用模板化的f

标签: c++ vector iterator c++17 assign


【解决方案1】:

范围版本更适合vec.assign(5, 10);InputIt = int。您应该以某种方式禁用不代表输入迭代器的模板参数的重载。

我们来看看stdlibc++ implementation

template<typename InputIt, typename = std::RequireInputIter<InputIt>>
void assign(InputIt first, InputIt last) {
    M_assign_dispatch(first, last);
}

在哪里RequireInputIteris

template<typename InputIt>
using RequireInputIter = typename enable_if<is_convertible<typename
    iterator_traits<InputIt>::iterator_category, input_iterator_tag>::value>::type;

换句话说,对于推导类型InputItiterator_traits&lt;InputIt&gt;::iterator_category 类型应该可以转换为input_iterator_tag。否则,由于SFINAEassign 重载会被静默排除在重载解决方案集中。

在 C++17 中,RequireInputIter 可以简化为 _t_v 助手:

template<typename InputIt>
using RequireInputIter = enable_if_t<is_convertible_v<typename
    iterator_traits<InputIt>::iterator_category, input_iterator_tag>>;

另请注意,输入迭代器可用于遍历范围only once。在您调用std::distance(first, last) 之后,所有后续遍历范围的尝试都是未定义的行为,除非InputIt 至少是一个前向迭代器。对于输入迭代器,您无法确定要预分配多少空间。

这就是assign 在内部使用标签调度技术的原因。经过一些简化,它看起来像这样:

template<typename InputIt, typename = std::RequireInputIter<InputIt>>
void assign(InputIt first, InputIt last) {
    M_assign_aux(first, last, 
        typename iterator_traits<InputIt>::iterator_category{});
}

有两个M_assign_aux 重载

template<typename InputIt>
void M_assign_aux(InputIt first, InputIt last, std::input_iterator_tag);

template<typename ForwardIt>
void M_assign_aux(ForwardIt first, ForwardIt last, std::forward_iterator_tag);

完成任务。第一个仅用于输入迭代器,第二个用于前向迭代器和从它派生的迭代器,即双向和随机访问迭代器。

【讨论】:

  • 非常感谢。这正是我需要的:)
  • @RadicalEdward,更新了迭代器类别的标签调度。
【解决方案2】:

您可以使用强制转换调用特定函数。喜欢: 赋值( (size_t) 5, (const int&) 10);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-22
    • 2016-05-02
    • 2012-02-12
    • 1970-01-01
    • 1970-01-01
    • 2017-09-19
    相关资源
    最近更新 更多