如果我将类代码放在同一个标头或同一个
.cpp
文件中,则不会出现此问题,但是当我将类规范放在标头中并将类代码放在单独的 .cpp
文件中时,我得到了这个编译时出错main.cpp
:
/usr/bin/ld: ex2.o: in function `main':
ex2.cpp:(.text+0xd0): undefined reference to `std::ostream& operator<< <int>(std::ostream&, array<int> const&)'
/usr/bin/ld: ex2.cpp:(.text+0xe6): undefined reference to `std::ostream& operator<< <float>(std::ostream&, array<float> const&)'
/usr/bin/ld: ex2.cpp:(.text+0xfc): undefined reference to `std::ostream& operator<< <double>(std::ostream&, array<double> const&)'
collect2: error: ld returned 1 exit status
我找不到解决这个问题的方法。我什至在未定义引用模板运算符并在同一头文件中定义尝试了接受的解决方案,但它不起作用,我收到其他错误。
那么,有没有办法解决这个问题呢?我是否只需将
class.cpp
代码放入头文件中(或包含它)?以下是每个文件的代码。
数组.h
#ifndef ARRAY_H
#define ARRAY_H
#include <ostream>
template <typename T>
class array {
public:
array (int size);
array (const array<T> &ob);
~array ();
void setElemet (T value, int pos);
int getElement (int pos) const;
int getSize() const;
void arrayInit ();
int operator[](int pos);
array<T> &operator=(const array<T> &right);
array<T> &operator+=(int right);
template <typename U> friend std::ostream &operator<<(std::ostream &left, const array<U> &right);
private:
T *arr;
int size;
};
#endif
数组.cpp
#include <iostream>
#include "array.h"
#include <random>
using std::cout, std::endl;
template class array<int>;
template class array<float>;
template class array<double>;
template <typename T>
array<T>::array(int size) {
this -> size = size;
if(this -> size <= 0) {
if(this -> size == 0)
this -> size = 1;
else
this -> size *= -1;
cout << "Array size corrected, current size = " << this -> size << "." << endl;
}
try {
arr = new T[this -> size];
} catch (const std::exception& ex) {
cout << "Memory allocation failed, reason: " << ex.what() << endl;
std::terminate();
}
arrayInit();
}
template <typename T>
array<T>::array(const array<T> &ob) {
this -> size = ob.size;
try {
arr = new T[this -> size];
} catch (const std::exception& ex) {
cout << "Memory allocation failed, reason: " << ex.what() << endl;
std::terminate();
}
for (int i = 0; i < size; i++) {
arr[i] = ob.arr[i];
}
}
template <typename T>
array<T>::~array () {
delete[] arr;
}
template <typename T>
void array<T>::setElemet (T value, int pos) {
if(pos < 0 || pos >= size) {
cout << "Invalid position, array ranges from 0 to " << size - 1 << "." << endl;
} else {
arr[pos] = value;
}
}
template <typename T>
int array<T>::getElement (int pos) const{
if(pos < 0 || pos >= size) {
cout << "Invalid position, array ranges from 0 to " << size - 1 << "." << endl;
return -1;
} else {
return arr[pos];
}
}
template <typename T>
int array<T>::getSize() const {
return size;
}
template <typename T>
void array<T>::arrayInit (){
std::random_device rd;
if(std::is_same<T, int>::value) {
std::uniform_int_distribution <int> dist (-10000, 10000);
for (int i = 0; i < size; i++) {
arr[i] = dist(rd);
}
} else if (std::is_same<T, float>::value) {
std::uniform_real_distribution <float> dist (-10000, 10000);
for (int i = 0; i < size; i++) {
arr[i] = dist(rd);
}
} else if (std::is_same<T, double>::value) {
std::uniform_real_distribution <double> dist (-10000, 10000);
for (int i = 0; i < size; i++) {
arr[i] = dist(rd);
}
}
}
template <typename T>
int array<T>::operator[](int pos) {
try {
if (pos < 0 || pos >= size)
throw pos;
return arr[pos];
} catch (int ex) {
cout << "Tried to input out of array size. Array ranges from 0 to " << size - 1 << ". Position tried to input: ";
return pos;
}
}
template <typename T>
array<T> &array<T>::operator=(const array<T> &right) {
if (this == &right) return *this;
for (int i = 0; i < size; i++) {
arr[i] = right.arr[i];
}
return *this;
}
template <typename T>
array<T> &array<T>::operator+=(int right) {
if (right <= 0) {
cout << "Can't expand array with negative or zero input." << endl;
return *this;
}
int oldSize = size;
array<T> temp(oldSize);
size += right;
temp = *this;
delete [] arr;
try {
arr = new T[size];
} catch(const std::exception& ex) {
cout << "Memory allocation failed, reason: " << ex.what() << endl;
std::terminate();
}
for (int i = 0; i < oldSize; i++) {
arr[i] = temp[i];
}
std::random_device rd;
if(std::is_same<T, int>::value) {
std::uniform_int_distribution <int> dist (-10000, 10000);
for (int i = 0; i < size; i++) {
arr[i] = dist(rd);
}
} else if (std::is_same<T, float>::value) {
std::uniform_real_distribution <float> dist (-10000, 10000);
for (int i = 0; i < size; i++) {
arr[i] = dist(rd);
}
} else if (std::is_same<T, double>::value) {
std::uniform_real_distribution <double> dist (-10000, 10000);
for (int i = 0; i < size; i++) {
arr[i] = dist(rd);
}
}
return *this;
}
template <typename T>
std::ostream &operator<<(std::ostream &left, const array<T> &right) {
if(right.size <= 0) {
left << "Array size invalid." << "endl";
} else {
for(int i = 0; i < right.size; i++) {
left << "Array element " << i << " has a value = " << right.arr[i] << "." << endl;
}
}
return left << endl;
}
ex2.cpp
#include <iostream>
#include "array.h"
using std::cout, std::cin, std::endl;
int main() {
array<int> arr1(3);
array<float> arr2(3);
array<double> arr3(3);
cout << arr1;
cout << arr2;
cout << arr3;
return 0;
}
感谢@n.m.couldbeanAI,我发现解决方案是将以下 3 行放入我的 array.cpp 中
template std::ostream &operator<<(std::ostream &left, const array<int> &right);
template std::ostream &operator<<(std::ostream &left, const array<float> &right);
template std::ostream &operator<<(std::ostream &left, const array<double> &right);
它有效,但我每个都收到一个警告(我收到另外两个类似的警告):
warning: friend declaration ‘template<class U> std::ostream& operator<<(std::ostream&, const array<U>&’ is not visible to explicit specialization 10 | template std::ostream &operator<<(std::ostream &left, const array<int> &right); ^~~~~~~~
In file included from array.cpp:2: array.h:22:52: note: friend declaration here 22 | template <typename U> friend std::ostream &operator<<(std::ostream &left, const array<U> &right);
这正常吗?