在c++ 11中定义在另一个文件中的函数模板?



我写了一个自定义向量类模板和print_vector函数模板,应该打印我的自定义向量类的内容。print_vector函数使用在vector类内部声明为私有的v.szv.elem。然而,我无法将print_vector声明为vector类中的朋友。我想保持print_vector单独定义在t_vector.cpp

问题是print_vector接受的形参类型与声明它为友类的类相同(变成了循环依赖?)我还得到一个错误,说print_vector没有在作用域中声明。

我用// <--标记了有问题的地方

// t_vector.h
#ifndef T_VECTOR_H
#define T_VECTOR_H
#include <string>
template <typename T>
void print_vector(Vector<T>& v);
template <typename T>
struct Vector {
private:
int sz;
T* elem;
public:
Vector() = delete;
explicit Vector(int s);
Vector(const Vector<T>& v); 
~Vector(); 
Vector<T>& operator=(const Vector<T>& v); 
T& operator[](int e) const;
template<typename U>
friend void print_vector(Vector<U>& v); // <-- TRYING TO FRIEND print_vector
};
#endif
// t_vector.cpp
#include "t_vector.h"
#include <stdexcept>
#include <iostream>
#include <string>
using std::cout;
using std::endl;
using std::string;
template <typename T>
Vector<T>::Vector(int s) {
if (s < 0) throw std::invalid_argument("Negative size");
cout << this << " called Vector(int s) constructor" << endl;
sz = s;
elem = new T[sz];
}
template <typename T>
Vector<T>::Vector(const Vector<T>& v) : sz{v.sz}, elem{new T[v.sz]} { 
cout << this << " called Copy constructor on " << &v << endl;
for (int i = 0; i<sz; ++i) {
elem[i] = v[i];
}
}
template <typename T>
Vector<T>::~Vector() {
cout << "~" << this << " delete elem " << &elem << endl;
delete[] elem;
}
template <typename T>
Vector<T>& Vector<T>::operator=(const Vector<T>& v) {
cout << this << " called Copy assignment operator to copy " << &v << endl;
if (this != &v) {
T *tmp = new T[v.sz];
for (int i=0; i<v.sz; ++i ) {
tmp[i] = v.elem[i];
}
sz = v.sz; 
delete[] elem;
elem = tmp;
}
return *this;
}
template <typename T>
T& Vector<T>::operator[](int e) const {
if (e < 0 || e >= sz) throw std::out_of_range("Vector::operator[]"); 
return elem[e];
}
template <typename T>
void print_vector(Vector<T>& v) { // <--- THIS FUNCTION WANTS TO READ v.sz WHICH IS PRIVATE
for (int i = 0; i < v.sz-1; ++i) {
cout << '[' << v.elem[i] << ']';
}
cout << '[' << v[v.sz-1] << ']' << endl;
}
// test_t_vector.cpp
#include "t_vector.h"
#include "t_vector.cpp" 
#include <iostream>
using std::cout;
using std::endl;
int main() {
cout << "---------- Starting: test_vector ----------" << endl;
Vector<int> vec(3);

vec[2] = 5;
print_vector(vec);
cout << "---------- Exiting: test_vector ----------" << endl;
return 0; 
}

错误输出:

g++ -O0 -Wall -Wextra -pedantic-errors -Wold-style-cast  -fno-elide-constructors  -std=c++14  -g -ggdb3  -MT t_vector.o -MMD -MP -MF t_vector.d -std=c++14 -I.  -c -o t_vector.o t_vector.cpp
In file included from t_vector.cpp:1:
t_vector.h:7:6: error: variable or field ‘print_vector’ declared void
7 | void print_vector(Vector<T>& v);
|      ^~~~~~~~~~~~
t_vector.h:7:19: error: ‘Vector’ was not declared in this scope
7 | void print_vector(Vector<T>& v);
|                   ^~~~~~
t_vector.h:7:27: error: expected primary-expression before ‘>’ token
7 | void print_vector(Vector<T>& v);
|                           ^
t_vector.h:7:30: error: ‘v’ was not declared in this scope
7 | void print_vector(Vector<T>& v);
|                              ^
make: *** [<builtin>: t_vector.o] Error 1

正如Ted Lyngmo和Retired Ninja所提到的,问题在于实现应该在头文件中可见。实现这一点的方法之一是在头文件中包含一个带有所有模板实现的.tpp文件,并将该文件包含在头文件的末尾。不幸的是,尽管将头文件中的类模板声明和cpp文件中的实现细节分开,我的类模板似乎仍然可以工作。这可能是偶然发生的,但一般规则是在头文件中以某种方式显示实现细节。

最新更新