C++-如何为类模板声明函数模板友元
C++ - How to declare a function template friend for a class template
我有一个类模板,它将输出存储在数组中的对象列表。我得到了以下错误,我很困惑错误是在哪里引起的,因为错误在.obj和.exe文件中。
1个未解析的外部文件(proj08.exe第1行)
未解析的外部符号"class std::basic_stream>&__cdecl运算符<<(class std::basic_stream>>,class MyVector)"(?6@YAAAV$basic_ostream@DU$char_traits@D@std@@@std@@AAV01@V$MyVector@N@@@Z) 在函数_main(porj08.obj第1行)中引用
proj08.cpp
#include "stdafx.h"
#include <string>
#include "MyVector.h"
const double FRACTION = 0.5;
int main()
{
cout << "nCreating a vector of doubles named Samn";
MyVector<double> sam;
cout << "nPush 12 values into the vector.";
for (int i = 0; i < 12; i++)
sam.push_back(i + FRACTION);
cout << "nHere is sam: ";
cout << sam;
cout << "n---------------n";
cout << "nCreating an empty vector named joe";
MyVector<double> joe;
// test assignment
joe = sam;
cout << "nHere is joe after doing an assignment:n ";
cout << joe;
cout << "n---------------n";
// test the copy constructor
MyVector<double> bill = sam;
cout << "nHere is bill after creating it using the copy constructor:n ";
cout << bill;
cout << "n---------------n";
cout << endl;
system("PAUSE");
return 0;
}
MyVector.h
#pragma once
#include <iostream>
#include "stdafx.h"
using namespace std;
template <class T>
class MyVector
{
private:
int vectorSize;
int vectorCapacity;
T *vectorArray;
public:
MyVector() {
vectorArray = new T[10];
}
T size();
T capacity();
void clear();
void push_back(T n);
T at(int n);
friend ostream& operator<<(ostream& os, MyVector<T> vt);
MyVector<T> operator=(MyVector<T>&);
};
/*
* TEMPLATE FUNCTIONS
*/
//Return array size
template<class T>
T MyVector<T>::size()
{
return vectorSize;
}
// Return array capacity
template<class T>
T MyVector<T>::capacity()
{
return vectorCapacity;
}
// clear array values
template<class T>
void MyVector<T>::clear()
{
for (int i = 0; i < vectorSize; i++)
{
vectorArray[i] = ' ';
}
vectorSize = 0;
vectorCapacity = 2;
}
// Add number to array and double array size if needed
template<class T>
void MyVector<T>::push_back(T n)
{
int test = 100;
if (vectorCapacity > vectorSize)
{
vectorArray[vectorSize] = n;
vectorSize++;
}
else {
if (vectorCapacity == 0) {
vectorArray = new T[4];
vectorArray[0] = n;
vectorCapacity = 4;
vectorSize++;
}
else {
int newCapacity = vectorCapacity * 2;
// Dynamically allocate a new array of integers what is somewhat larger than the existing array.An algorithm that is often used is to double the size of the array.
int *tempArray = new int[newCapacity];
// Change capacity to be the capacity of the new array.
vectorCapacity = newCapacity;
// Copy all of the numbers from the first array into the second, in sequence.
for (int i = 0; i < MyVector::size(); i++)
{
tempArray[i] = vectorArray[i];
}
delete[] vectorArray;
vectorArray = new T[newCapacity];
for (int i = 0; i < MyVector::size(); i++)
{
vectorArray[i] = tempArray[i];
}
delete[] tempArray;
// Add the new element at the next open slot in the new array.
vectorArray[vectorSize] = n;
// Increment the size;
vectorSize++;
}
}
}
// Return Value and given point in array
template<class T>
T MyVector<T>::at(int n)
{
return vectorArray[n];
}
// Set one vector to equil another
template<class T>
MyVector<T> MyVector<T>::operator=(MyVector<T>& right) {
if (vectorCapacity < right.vectorCapacity) {
if (vectorCapacity != 0)
delete[] vectorArray;
vectorArray = new T[right.vectorCapacity];
vectorCapacity = right.vectorCapacity;
}
vectorSize = right.size();
// Assign values from left to right
for (int i = 0; i < vectorSize; i++)
{
vectorArray[i] = right.at(i);
}
return *this;
}
// Cout Vector
template<class T>
ostream& operator << (ostream& os, MyVector<T> vt)
{
T size = vt.size();
for (T i = 0; i < size; i++) {
os << "index " << i << " is " << vt.at(i) << endl;
}
return os;
}
如果您想匹配您定义的函数模板,则必须将friend
声明为函数模板:
template <typename U> // use U, so it doesn't clash with T
friend ostream& operator<<(ostream& os, MyVector<U> vt);
如果为类模板声明了friend
函数,则不会使其成为函数模板
@LogicStuff的答案是完全有效的。我想澄清一下你的代码中到底发生了什么,以及如何使用替代方案来避免它,因为我相信大多数C++程序员至少遇到过一次这个问题。基本上,当模板被实例化时,比如
MyVector<int> something;
然后friend
声明自动绑定到模板类型,在本例中为int
,因此编译器生成
friend ostream& operator<<(ostream& os, MyVector<int> vt);
然而,这只是一个宣言。您的后一种定义
template<class T>
ostream& operator << (ostream& os, MyVector<T> vt)
与int
没有任何关系,因为前者更匹配,所以无论何时尝试
cout << something;
编译器尝试调用CCD_ 6版本(其没有定义)。所以你得到了一个链接器错误。
一种广泛使用的替代方法是在类中内联定义操作员,如
friend ostream& operator << (ostream& os, MyVector<T> vt)
{
T size = vt.size();
for (T i = 0; i < size; i++) {
os << "index " << i << " is " << vt.at(i) << endl;
}
return os;
}
现在,MyVect
的每个实例化都会生成一个绑定到相应模板类型的operator<<
的有效定义。请注意,运算符本身不是成员函数,它在全局命名空间中仅通过参数依赖查找(ADL)可见。这个技巧被称为朋友名字注入,在巴顿-纳克曼技巧中广泛使用,你能够成功地使用它,因为在像这样的调用中
cout << something;
呼叫被转换为
operator<< (std::cout, something)
由于something
属于MyVector<int>
型,因此通过ADL找到了operator<<
的定义。如果您的operator<<
将例如int
作为第二个参数,则无法通过ADL找到它,因为基本类型没有关联的命名空间。
- 在模板类中声明非模板函数?
- 我应该声明我的函数模板专业化还是定义它们就足够了
- 如何在C++模板中声明函数
- 声明一个模板函数,将模板类友元的两个对象(仅)带到这两个专用化
- 使用非类型模板参数正向声明函数模板
- 如何声明接受转发引用并返回引用或副本的函数模板
- 如何在C 中声明外部CUDA函数模板
- SFINAE 消除、Constexpr 和函数模板:我可以将声明和定义分开吗?
- 声明一个模板函数,该函数接收两个泛型迭代器作为参数
- MISRA C++规则 14-5-1:在与类型关联的命名空间中声明的泛型函数模板的名称
- 无法声明函数中的模板类型别名
- 如何将函数指针声明指向模板函数,其返回类型取决于模板类
- 如何在同一个主文件中转发声明类似模板函数的模板类
- 'Incomplete type' 为标准::函数声明指向成员的指针函数模板参数时出错
- 声明函数模板的5种新语法是什么
- 声明采用模板参数的函数
- 将依赖类型声明为模板类中的函数参数
- C++-如何为类模板声明函数模板友元
- 重载时在定义之前声明函数模板
- 声明函数模板的语法