与 C++11 中另一个文件中定义的函数模板成为朋友?
Befriending a function template defined in another file in C++11?
我已经编写了一个自定义向量 class 模板和 print_vector 函数模板,它们应该打印我的自定义向量 class 的内容。 print_vector 函数使用 v.sz
和 v.elem
,它们在向量 class 中声明为私有。但是我无法在我的向量 class 中将 print_vector 声明为朋友。我想在 t_vector.cpp
.
中单独定义 print_vector
一个问题是 print_vector 接受一个与 class 相同类型的参数,它在其中被声明为友元(成为循环依赖?)。我还收到一条错误消息,指出 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 所提到的,问题是实施应该在 header 文件中可见。实现此目的的方法之一是在 header 文件中包含一个包含所有模板实现的 .tpp 文件,并将此文件包含在 header 文件的末尾。不幸的是,尽管 header 文件中的 class 模板声明与 cpp 文件中的实现细节分开,但我的 class 模板似乎仍然有效。这可能靠运气发生,但一般规则是以 header 一种或另一种方式显示实施细节。
我已经编写了一个自定义向量 class 模板和 print_vector 函数模板,它们应该打印我的自定义向量 class 的内容。 print_vector 函数使用 v.sz
和 v.elem
,它们在向量 class 中声明为私有。但是我无法在我的向量 class 中将 print_vector 声明为朋友。我想在 t_vector.cpp
.
一个问题是 print_vector 接受一个与 class 相同类型的参数,它在其中被声明为友元(成为循环依赖?)。我还收到一条错误消息,指出 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 所提到的,问题是实施应该在 header 文件中可见。实现此目的的方法之一是在 header 文件中包含一个包含所有模板实现的 .tpp 文件,并将此文件包含在 header 文件的末尾。不幸的是,尽管 header 文件中的 class 模板声明与 cpp 文件中的实现细节分开,但我的 class 模板似乎仍然有效。这可能靠运气发生,但一般规则是以 header 一种或另一种方式显示实施细节。