【问题标题】:Some friend functions of a template class exhibit undefined reference模板类的一些友元函数表现出未定义的引用
【发布时间】:2021-08-05 00:46:10
【问题描述】:

最初是在研究其他人之前提出的问题: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&lt;std::__cxx11::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt; &gt; const&amp;)'

我找到了两种解决方法:

  1. Array 类中定义DataOut
  2. 在 main 中调用 DataOut&lt;std::String&gt;,而不仅仅是 DataOut

问题是,GetData 怎么没有出错?我还尝试以不同的顺序调用和定义它们,但结果仍然相同。

我有什么遗漏吗?还是我的编译器 (clang 7.0.0) 的错?

【问题讨论】:

    标签: c++ templates friend friend-function


    【解决方案1】:

    你声明了两个(家族)非模板友元函数

    template<class T>
    class Array{
    public:
        T U[10];
    
        friend void DataOut(const Array&);
        friend void GetData(Array&);
    };
    

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

    这是一个演示程序。

    #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>() );
    

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

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

    就是这个函数模板声明

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

    与非模板友元函数DataOut没有任何共同之处。

    关于这个问题

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

    那么你在类内和类外命名函数时有一个错字。那就是你有两个不同的函数GetDataGetdata

    【讨论】:

    • @Ranoiaetep 你看到 GetData 和 getData 是两个不同的名字了吗?那就是你打错了,并声明了两个不同名称的函数。
    【解决方案2】:

    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`
    }
    

    【讨论】:

    • 请注意,这会使朋友成为模板。在OP中它不是。这可能会导致一些行为变化。
    猜你喜欢
    • 1970-01-01
    • 2016-10-19
    • 2011-05-16
    • 2016-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-19
    相关资源
    最近更新 更多