更新:O'Neil发现了粗心错误:我使用operator!=
定义了const
,但在声明中省略了const
。这当然也解释了为什么在类声明中放置完整的函数定义最初解决了问题。
我试图为C ++实现一个简单的标准库(用于学习目的),并且在调用与迭代器关联的operator==
和operator!=
时遇到链接器错误通过矢量。
注意:我已经将很多代码包含在内,但您应该只能查看vector::insert
,operator!=(iterator, iterator)
和{{1}的内容除了底部所述的链接错误外,还要找出问题。
我已经实现了vector.hpp,省略了一些我认为不足以确定错误原因的定义:
main
实现了iterator.hpp
#ifndef VECTOR_HPP
#define VECTOR_HPP
#include "utility.hpp" // stl::size_t
#include "memory.hpp" // stl::Allocator
#include "iterator.hpp"
namespace stl {
template <typename T, typename A>
class VectorBase
{
public:
typedef T ValueType;
typedef T& Reference;
typedef const T& ConstReference;
typedef T* Pointer;
typedef const T* ConstPointer;
typedef A AllocatorType;
typedef stl::size_t SizeType;
VectorBase(SizeType, const AllocatorType&);
~VectorBase() { delete[] elements_; }
AllocatorType allocator_;
Pointer elements_ = nullptr;
SizeType size_ = 0;
SizeType capacity_ = 0;
};
template <typename T, typename A = stl::Allocator<T> >
class Vector : private VectorBase<T, A>
{
public:
typedef typename VectorBase<T, A>::AllocatorType AllocatorType;
typedef stl::BidirectionalIterator<T> Iterator;
typedef const stl::BidirectionalIterator<T> ConstIterator;
typedef typename VectorBase<T, A>::ValueType ValueType;
typedef typename VectorBase<T, A>::Reference Reference;
typedef typename VectorBase<T, A>::ConstReference ConstReference;
typedef typename VectorBase<T, A>::Pointer Pointer;
typedef typename VectorBase<T, A>::ConstPointer ConstPointer;
typedef Vector<T, A> Self;
typedef typename VectorBase<T, A>::SizeType SizeType;
// CONSTRUCTORS & DESTRUCTORS
Vector(SizeType = 0,
ValueType&& = ValueType(),
const AllocatorType& = AllocatorType());
Vector(const Self&);
Vector(Self&&);
Self& operator=(Self);
// OPERATORS
Reference operator[](SizeType);
ConstReference operator[](SizeType) const;
// MODIFIERS
Iterator insert(Iterator, ValueType);
void pop_back();
void push_back(ValueType);
void reserve(SizeType);
template <typename T_, typename A_>
friend void swap(Vector<T_, A_>&, Vector<T_, A_>&);
// ACCESSORS
Iterator begin();
ConstIterator cbegin() const;
Iterator end();
ConstIterator cend() const;
};
template <typename T, typename A>
auto Vector<T, A>::insert(Iterator iterator, ValueType val) -> Iterator
{
if (this->size_ == this->capacity_)
reserve(2 * this->size_);
for (auto it = this->end(); it != iterator; --it) { // this is the problem line
// for (auto it = this->end(); stl::operator!=(it, iterator); --it) { // this fixes the linking issue
auto temp(it);
*temp = *--it;
++it;
}
*iterator = stl::move(val);
return iterator;
}
// ...
} // namespace stl
#endif // VECTOR_HPP
最后test.cpp是
#ifndef ITERATOR_HPP
#define ITERATOR_HPP
#include "utility.hpp"
namespace stl {
template <typename T>
struct BidirectionalIterator
{
typedef T ValueType;
typedef T* Pointer;
typedef const T* ConstPointer;
typedef T& Reference;
typedef const T& ConstReference;
typedef BidirectionalIterator<T> Self;
BidirectionalIterator(Pointer ptr = nullptr) : current_(ptr) { }
BidirectionalIterator(const Self& that) : current_(that.current_) { }
BidirectionalIterator(Self&&);
Self& operator=(Self);
Self& operator++();
Self operator++(int);
Self& operator--();
Self operator--(int);
Reference operator*();
ConstReference operator*() const;
Pointer operator->();
ConstPointer operator->() const;
template <typename T_>
friend void swap(BidirectionalIterator<T_>&,
BidirectionalIterator<T_>&);
template <typename T_>
friend bool operator==(BidirectionalIterator<T_>&,
BidirectionalIterator<T_>&);
template <typename T_>
friend bool operator!=(BidirectionalIterator<T_>&,
BidirectionalIterator<T_>&);
Pointer current_;
};
template <typename T>
bool operator==(const BidirectionalIterator<T>& first,
const BidirectionalIterator<T>& second)
{ return first.current_ == second.current_; }
template <typename T>
bool operator!=(const BidirectionalIterator<T>& first,
const BidirectionalIterator<T>& second)
{ return !(first == second); }
// ...
} // namespace stl
#endif // ITERATOR_HPP
然后当我尝试编译:
#include <iostream>
#include "../include/vector.hpp"
int main(void)
{
stl::Vector<int> v;
for (stl::size_t i = 0; i < 5; ++i)
v.push_back(i);
for (auto it = v.begin(); it != v.end(); ++it)
std::cout << *it << std::endl;
std::cout << std::endl;
v.pop_back();
for (auto it = v.begin(); it != v.end(); ++it)
std::cout << *it << std::endl;
std::cout << std::endl;
auto it = v.begin();
++it;
v.insert(it, 100);
for (auto it = v.begin(); it != v.end(); ++it)
std::cout << *it << std::endl;
}
我得到了
$ clang++ test.cpp -std=c++11 // I get the same issue with g++
但是,如果我在Undefined symbols for architecture x86_64:
"bool stl::operator!=<int>(stl::BidirectionalIterator<int>&, stl::BidirectionalIterator<int>&)", referenced from:
stl::Vector<int, stl::Allocator<int> >::insert(stl::BidirectionalIterator<int>, int) in test-dbe290.o
ld: symbol(s) not found for architecture x86_64
中取出v.insert(it, 100);
,该程序就可以了。此外,如果我留下main
,并按上述评论中的说明修复v.insert(it, 100);
(即,将vector::insert
从非限定函数调用更改为operator!=
限定函数调用) ,整个程序链接正常,并产生预期的结果。我似乎未能正确调用ADL,因此我查看了adl according to cppreference.com的详细信息,以查找添加到查找中的其他命名空间并找到:
2)对于类类型的参数(包括union),该集合包含 ... d)添加到集合
中的类中最内层的封闭命名空间
由于stl
中包含BidirectionalIterator
,我认为stl
应包含在查找中,并且不需要明确说明。
另一个有趣的事情是,如果我将stl::operator!=
更改为在operator!=
类中完全定义,即:
BidirectionalIterator
并恢复导致错误的先前代码:template <typename T_>
friend bool operator!=(BidirectionalIterator<T_>& first,
BidirectionalIterator<T_>& second)
{ return !(first == second); }
中的for (auto it = this->end(); it != iterator; --it) {
,vector::insert
中的insert
调用正常,但另一个用于循环(即{{ 1}})导致以下编译器错误:
main
为什么编译器在没有显式范围解析运算符的情况下能够在for (auto it = v.begin(); it != v.end(); ++it)
中找到error: invalid operands to binary expression ('stl::BidirectionalIterator<int>' and 'Iterator' (aka 'BidirectionalIterator<int>'))
for (auto it = v.begin(); it != v.end(); ++it)
?另外,为什么在operator!=
的类声明中完全定义友元函数解决了第一个问题,但直接在stl
中导致BidirectionalIterator
实例的编译器错误?