模板 class 的一些友元函数显示未定义的引用

Some friend functions of a template class exhibit undefined reference

最初正在研究其他人之前提出的问题:Why string is not printed?C++。看到 OP 没有充分利用 DataOutGetData 的模板,所以我也尝试将它们设为模板。

这是我最终得到的代码:

#include <iostream>
#include <string>

template<class T>
class Array{
public:
    T U[10];

    friend void DataOut(const Array&);
    friend void GetData(Array&);
};

template<class T>
void DataOut(const Array<T>& arr){
    std::cout << arr.U[0];
}

template<class T>
void Getdata(Array<T>& arr){
    std::cin >> arr.U[0];
    std::cin.clear();
}

int main(){
    Array<std::string> Arr1;
    Getdata(Arr1);
    DataOut(Arr1);
}

但是,我得到了 DataOut 的未定义引用:main.cpp:(.text+0x3a): undefined reference to 'DataOut(Array<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&)'

我找到了两种解决方法:

  1. 定义DataOut里面的Arrayclass.
  2. 在 main 中调用 DataOut<std::String>,而不仅仅是 DataOut

问题来了,GetData怎么没有报错呢?我也试过以不同的顺序调用和定义它们,但仍然是相同的结果。

有什么我想念的吗?或者这是我的编译器 (clang 7.0.0) 的错误?

您声明了两个(的)非模板友元函数

template<class T>
class Array{
public:
    T U[10];

    friend void DataOut(const Array&);
    friend void GetData(Array&);
};

如果您希望这样的非模板函数成为 class 模板特化的友元函数,您必须为该特化显式定义它。

这是一个演示程序。

#include <iostream>
#include <iomanip>
#include <string>

template <typename T>
class A
{
private:
    T x = T();
    
    friend void f( const A & );
};

void f( const A<int> &a )
{
    std::cout << "a.x = " << a.x << '\n';
}

void f( const A<std::string> &a )
{
    std::cout << std::boolalpha << "a.x is empty = " << a.x.empty() << '\n';
}

int main() 
{
    f( A<int>() );
    f( A<std::string>() );
    
    return 0;
}

它的输出是

a.x = 0
a.x is empty = true

例如,如果您将在 main

中添加以下语句
f( A<long>() );

那么编译器会报错,因为没有这样的非模板函数。 class 模板的这种特殊化的函数未定义。

您可以在 class 中定义好友非模板函数。在这种情况下,编译器将为 class 模板的每个特化实例化所谓的模板化实体。

也就是这个函数模板声明

template<class T>
void DataOut(const Array<T>& arr){
    std::cout << arr.U[0];
}

与非模板友元函数没有任何共同点DataOut

关于这个问题

The question is, how come no errors happens to GetData? I also tried to call and define them in different orders, but still the same result.

那么你在 class 和 class 之外的函数命名有一个错字。那就是你有两个不同的函数 GetDataGetdata.

Vlad 回答了我的大部分问题。同时,我想出了如何从一些 gcc 警告中将友元函数定义为模板函数:

template<class T>
class Array;         // Forward declaration of the Array<T> class

template<class T>
void DataOut(const Array<T>& arr){
    std::cout << arr.U[0];
}

template<class T>
class Array{
public:
    T U[10];

    friend void DataOut<>(const Array<T>&);    // `<>` used right after `DataOut`
}