gpt4 book ai didi

c++ - 模板化运算符的奇怪行为<<

转载 作者:太空宇宙 更新时间:2023-11-04 15:19:33 24 4
gpt4 key购买 nike

我无法理解我类运算符<<的行为:

标题:

#ifndef VECTOR_H_
#define VECTOR_H_

#include <string>
#include <iostream>

template<class T>
class Vector {
static const int EXPANDER = 10;
T* array;
int next;
int length;
void expand();
void contract();
public:
Vector();
Vector(const Vector& v);
void add(const T e);
T get(int index) const;
bool removeByIndex(int index);
bool remove(T e);
int size() const;

T operator[](int i) const;
T& operator+=(const T& t);
T operator+(const T& s);

friend std::ostream& operator<< (std::ostream& os, const Vector<T>& obj);
friend std::istream& operator>> (std::istream& is, Vector<T>& obj);

std::string toString();
~Vector();
};

#endif /* VECTOR_H_ */

vector .cpp

#include "Vector.h"
#include <string>
#include <sstream>

template<class T>
Vector<T>::Vector() {
length = EXPANDER;
next = 0;
array = new T[EXPANDER];
}

template<class T>
Vector<T>::Vector(const Vector& v) {
length = v.next + 1 + EXPANDER;
next = v.next;
array = new T[length];
for (int i = 0; i <= v.next; i++) {
array[i] = v.array[i];
}
}

template<class T>
void Vector<T>::add(const T e) {
if (next >= length - 1)
expand();
array[next++] = e;
}

template<class T>
T Vector<T>::get(int index) const {
if (index > next)
return -1;
return array[index - 1];
}

template<class T>
bool Vector<T>::removeByIndex(int index) {
if (index > next)
return false;
for (int i = index; i < length; i++) {
array[i] = array[i + 1];
}
next--;
contract();
return true;
}

template<class T>
bool Vector<T>::remove(T e) {
int index = -1;
for (int i = 0; i < next; i++) {
if (array[i] == e) {
index = i;
break;
}
}
if (index == -1)
return false;
return removeByIndex(index);
}

template<class T>
int Vector<T>::size() const {
return next;
}

template<class T>
void Vector<T>::expand() {
length += EXPANDER;
T* temp = new T[length];
for (int i = 0; i < next; i++) {
temp[i] = array[i];
}
delete[] array;
array = temp;
}

template<class T>
void Vector<T>::contract() {
if (next + EXPANDER >= length)
return; // NO need to contract

length = next + EXPANDER + 1;
T* temp = new T[length];
for (int i = 0; i < next; i++) {
temp[i] = array[i];
}
delete[] array;
array = temp;
}

template<class T>
T Vector<T>::operator[](int i) const {
return get(i);
}

template<class T>
T& Vector<T>::operator+=(const T& t) {
for (int i = 0; i < t.size(); i++) {
add(t.get(i));
}
return *this;
}

template<class T>
T Vector<T>::operator+(const T& s) {
this += s;
return this;
}

template<class T>
std::ostream& operator<< (std::ostream& os, Vector<T>& obj) {
os << obj.toString();
return os;
}

template<class T>
std::istream& operator>> (std::istream& is, Vector<T>& obj) {
int size;
T temp;
is >> size;
for (int i = 0; i < size; i++) {
is >> temp;
add(temp);
}
return is;
}

template<class T>
std::string Vector<T>::toString() {
using namespace std;
ostringstream sb;
sb << "Elements(" << size() << "): [";
for (int i = 0; i < next; i++) {
sb << array[i] << ", ";
}
string r;
r = sb.str();
r = r.substr(0, r.size() - 2) + string("]");
return r;
}

template<class T>
Vector<T>::~Vector() {}

然后我用 main.cpp 运行这段代码

#include "Vector.h"
#include "Vector.cpp"
#include <string>
#include <iostream>
using namespace std;
int main() {
Vector<int> v;
v.add(1);
v.add(2);
cout << v << endl;
}

魔法就在operator<< header 中的声明。如果我删除 CONST 修饰符,编译器会说:Undefined reference to operator<< ,但使用 const 就可以了。有趣的是,在我的实现中,在 cpp 中,我没有 CONST。

顺便说一下,如何解决 warning: friend declaration declares a non-template function 的警告对于运营商?

最佳答案

您应该了解如何将其归结为 Short, Self-Contained, Compilable Example又名最小工作示例。

这是一个演示问题的 SSCCE:

#include <iostream>

template<class T>
class Vector
{
private:
T m;

public:
Vector(T p) : m(p) {}

friend std::ostream& operator<<(std::ostream& o, Vector<T> const& v);

T get() const { return m; }
};

template<class T>
std::ostream& operator<<(std::ostream& o, Vector<T>& v)
{
// accessing a private member leads to a compiler error here:
return o << "[function template]" << /*v.m*/ v.get();
}

// remove this function to get the same behaviour as in the OP
std::ostream& operator<<(std::ostream& o, Vector<int> const& v)
{
return o << "function" << v.m;
}

int main()
{
Vector<int> v(42);
std::cout << v;
}

请注意,它只有大约 30 行长,适合一个没有滚动条的屏幕。


现在,问题是基于类模板中的友元声明:

friend std::ostream& operator<<(std::ostream& o, Vector<T> const& v);

这会查找名为 operator<< 的函数在周围的范围内,与这个已经存在的功能成为 friend 。但它没有找到任何匹配这些参数类型的。因此,它在周围的(= 全局)命名空间中声明 一个新函数。这个函数看起来像这样:

std::ostream& operator<<(std::ostream& o, Vector<T> const& v);

(在全局命名空间中)注意:如果它仅通过友元声明声明,则只能通过参数依赖查找找到它。

现在,您稍后声明一个同名的函数模板。但是当您之前在您的类模板中编写友元声明时,编译器无法知道您打算与该函数模板成为友元。所以友元函数和函数模板这两个是不相关的

现在发生的是通常的重载决议。如果您不添加 const,则首选函数模板,因为您使用非 const 参数调用它:

Vector<int> v;
v.add(1);
v.add(2);
cout << v << endl; // v is not const

对于 Vector<int> 类型的参数, 绑定(bind)到 Vector<int>&函数模板(特化)的优先级高于对 Vector<int> const& 的绑定(bind)的 friend 功能。因此,选择了函数模板,它有一个定义(函数体),一切都可以编译、链接和工作。请注意,函数模板未成为 friend ,但这不会引发错误,因为您不使用任何私有(private)成员。

添加 const 后对于函数模板,函数模板不再是参数的更好匹配。由于我们有一个函数和一个具有相同重载“等级”的函数模板,因此首选非模板。因此,调用了 friend 函数,它没有定义 => 发生链接器错误。


最简单的解决方案是在类定义中定义友元函数:

template<class T>
class Vector
{
private:
T m;

public:
Vector(T p) : m(p) {}

friend std::ostream& operator<<(std::ostream& o, Vector<T> const& v)
{
return o << v.m;
}
};

使用前向声明的解决方案:

template<class T>
class Vector;

template<class T>
std::ostream& operator<<(std::ostream& o, Vector<T> const& v);

template<class T>
class Vector
{
private:
T m;

public:
Vector(T p) : m(p) {}

friend std::ostream& operator<< <T>(std::ostream& o, Vector<T> const& v);
};

template<class T>
std::ostream& operator<<(std::ostream& o, Vector<T> const& v)
{
return o << v.m;
}

现在,编译器可以找到前向声明的函数模板并与这个现有函数(函数模板的特化)友好,而不是声明一个新函数。


对整个函数模板友好的解决方案:

template<class T>
class Vector
{
private:
T m;

public:
Vector(T p) : m(p) {}

template<class U>
friend std::ostream& operator<<(std::ostream& o, Vector<U> const& v);
};

template<class T>
std::ostream& operator<<(std::ostream& o, Vector<T> const& v)
{
return o << v.m;
}

在此解决方案中,友元声明声明了一个函数模板,随后在类定义之后的命名空间范围内的声明重新声明此函数模板。

关于c++ - 模板化运算符的奇怪行为<<,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22584040/

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