与 C++11 中另一个文件中定义的函数模板成为朋友?

Befriending a function template defined in another file in C++11?

我已经编写了一个自定义向量 class 模板和 print_vector 函数模板,它们应该打印我的自定义向量 class 的内容。 print_vector 函数使用 v.szv.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 一种或另一种方式显示实施细节。