gpt4 book ai didi

c++ - 在自定义 vector 类中调用了错误的构造函数

转载 作者:行者123 更新时间:2023-11-30 04:03:35 26 4
gpt4 key购买 nike

我是 C++ 的新手,作为学习练习,我正在创建自己的简单 vector 类。

它似乎工作得很好,除了当我创建一个 Vec 对象试图使用
Vec(size_type n, const T& val = T()) 构造函数,它反而想使用应该采用两个迭代器/指针的模板化构造函数,并给我错误。

我相信我理解为什么会发生这种情况,但我想不出一种方法可以在不改变类的使用方式的情况下减少歧义。我想保持与 std::vector 相同的用法。

如何调用正确的构造函数? std::vector 如何避免这个问题?

Vec.h

//#includes: <algorithm> <cstddef> <memory>

template <class T> class Vec
{
public:
//typedefs for iterator, size_type....
//just used T* for iterator

Vec() { create(); }
Vec(const Vec& v) { create(v.begin(), v.end()); }
explicit Vec(size_type n, const T& val = T()) { create(n, val); }

template <class InputIt>
Vec(InputIt first, InputIt last) { create(first, last); }

~Vec() { uncreate(); }

T& operator[](size_type i) { return data[i]; }
const T& operator[](size_type i) const { return data[i]; }
Vec& operator=(const Vec&);

//functions such as begin(), size(), etc...

private:
iterator data;
iterator avail;
iterator limit;

std::allocator<T> alloc;
void create();
void create(size_type, const T&);

template <class InputIt>
void create(InputIt first, InputIt last)
{
data = alloc.allocate(last - first);
limit = avail = std::uninitialized_copy(first, last, data);
}

void uncreate();
void grow();
void unchecked_append(const T&);
};

template <class T>
Vec<T>& Vec<T>::operator=(const Vec& rhs)
{
if (&rhs != this)
{
uncreate();
create(rhs.begin(), rhs.end());
}
return *this;
}

template <class T> void Vec<T>::create()
{
data = avail = limit = 0;
}

template <class T> void Vec<T>::create(size_type n, const T& val)
{
data = alloc.allocate(n);
limit = avail = data + n;
std::uninitialized_fill(data, limit, val);
}

template <class T>
void Vec<T>::create(const_iterator i, const_iterator j)
{
data = alloc.allocate(j - i);
limit = avail = std::uninitialized_copy(i, j, data);
}

template <class T> void Vec<T>::uncreate()
{
if (data)
{
iterator it = avail;
while (it != data)
alloc.destroy(--it);
alloc.deallocate(data, limit - data);
}
data = limit = avail = 0;
}

//left out what I didn't think was relevant

除了我上面提到的情况,它似乎工作正常。

main.cpp

#include "Vec.h"

main()
{
Vec<int> v1(10, 100);
}

我收到错误:

||=== Build: Debug in Vec Class (compiler: GNU GCC Compiler) ===|c:\program files\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.7.1\include\c++\bits\stl_uninitialized.h||In instantiation of '_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = int; _ForwardIterator = int*]':|F:\CBProjects\Accelerated C++\Programming with Classes\Vec Class\Vec.h|58|required from 'void Vec::create(InputIt, InputIt) [with InputIt = int; T = int]'|F:\CBProjects\Accelerated C++\Programming with Classes\Vec Class\Vec.h|24|required from 'Vec::Vec(InputIt, InputIt) [with InputIt = int; T = int]'|F:\CBProjects\Accelerated C++\Programming with Classes\Vec Class\main.cpp|9|required from here|c:\program files\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.7.1\include\c++\bits\stl_uninitialized.h|113|error: no type named 'value_type' in 'struct std::iterator_traits'|||=== Build failed: 1 error(s), 4 warning(s) (0 minute(s), 0 second(s)) ===|

This is my first time asking a question on here. I hope I asked properly and provided enough information. Please let me know if I made a mistake in this process, and thank you for any help you can provide.

EDIT:

For anyone wondering what I ended up doing. I changed the templated constructor so that it won't be invoked with arithmetic arguments(since it's only meant for iterators/pointers).

template <class InputIt>
Vec(InputIt first, InputIt last,
typename std::enable_if<!std::is_arithmetic<InputIt>::value>::type* = 0) {create(first, last); }

它似乎工作正常,但实际上我对 enable_if 不是很熟悉,所以如果有人知道这种方法有任何危险,请告诉我。

最佳答案

选择模板构造函数是因为它更适合参数。

查看 vector constructor 的文档您会看到一条注释,指出如果参数满足 InputIterator 的要求,则此构造函数仅参与重载决策。这通常是通过使用 SFINAE 禁用过载来实现的。 .以下是 libcpp 是如何实现的。我试图删除一些不必要的部分并调整命名约定以提高可读性。

在实际实现中,此构造函数的通常定义如下所示:

template <class InputIterator>
vector(InputIterator first, InputIterator last,
typename enable_if<is_input_iterator <InputIterator>::value>::type* = 0);
template <class InputIterator>
vector(InputIterator first, InputIterator last, const allocator_type& a,
typename enable_if<is_input_iterator <InputIterator>::value>::type* = 0);

我删除了进一步区分 InputIteratorForwardIterator 的不必要部分。 SFINAE is the enable_if的重要部分及其参数。

下面是is_input_iterator的必要定义:

template <class Tp, class Up,
bool = has_iterator_category<iterator_traits<Tp> >::value>
struct has_iterator_category_convertible_to
// either integral_constant<bool, false> or integral_constant<bool, true>
: public integral_constant<
bool,
is_convertible<typename iterator_traits<Tp>::iterator_category, Up>::value
>
{};

// specialization for has_iterator_category<iterator_traits<Tp> >::value == false
template <class Tp, class Up>
struct has_iterator_category_convertible_to<Tp, Up, false> : public false_type {};

template <class Tp>
struct is_input_iterator
: public has_iterator_category_convertible_to<Tp, input_iterator_tag> {};

它的本质是检查给定类型是否具有可以转换为input_iterator_tagiterator_category标签。

has_iterator_category 就更晦涩了:

template <class Tp>
struct has_iterator_category
{
private:
struct two {char lx; char lxx;};
template <class Up> static two test(...);
template <class Up> static char test(typename Up::iterator_category* = 0);
public:
static const bool value = sizeof(test<Tp>(0)) == 1;
};

它用于检查给定类型是否具有名为 iterator_category 的成员。如果答案是nohas_iterator_category_convertible_to 将简单地默认为false_type。如果不这样做,将访问不存在的名称并触发硬编译器错误,这不是您想要在 SFINAE 中执行的操作。

关于c++ - 在自定义 vector 类中调用了错误的构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24346869/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com