C++ 为什么LNK1120&;LNK2019出现在模板和友元函数的情况下

C++ 为什么LNK1120&;LNK2019出现在模板和友元函数的情况下,c++,class,templates,friend-function,C++,Class,Templates,Friend Function,我已经用Turbo-C编译了第一个版本的代码,它编译时没有任何错误。但是,当我在VisualStudio或普通g++中从命令行编译这篇文章时,我会在文章中提到错误 我在互联网上搜索并阅读了一些StackOverflow问题和MSDN LNK1120问题文档。我找到了修复以下代码的方法。但是,没有弄清楚原因。一个定义怎么能消除这个错误呢。从语法上讲,容易出错的代码看起来也不错 1) Error 2 error LNK1120: 1 unresolved externals 2)

我已经用Turbo-C编译了第一个版本的代码,它编译时没有任何错误。但是,当我在VisualStudio或普通g++中从命令行编译这篇文章时,我会在文章中提到错误

我在互联网上搜索并阅读了一些StackOverflow问题和MSDN LNK1120问题文档。我找到了修复以下代码的方法。但是,没有弄清楚原因。一个定义怎么能消除这个错误呢。从语法上讲,容易出错的代码看起来也不错

1) Error    2   error LNK1120: 1 unresolved externals   

2) Error    1   error LNK2019: unresolved external symbol "void __cdecl  

totalIncome(class Husband<int> &,class Wife<int> &)" (?totalIncome@@YAXAAV?
$Husband@H@@AAV?$Wife@H@@@Z) referenced in function _main   
1)错误2错误LNK1120:1未解析的外部
2) 错误1错误LNK2019:未解析的外部符号“void\uu cdecl”
总收入(阶级丈夫和阶级妻子和阶级妻子)“(?总收入@@YAXAAV?
$Husband@H@@AAV$Wife@H@@@Z) 在函数_main中引用
注意:请注意程序中的箭头。我已经明确地提出了它们。因此,可能无法完成完整的程序

易出错代码:

#include <iostream>

using namespace std;

template<typename T> class Wife;           // Forward declaration of template    

template<typename T>
        class Husband{
        friend void totalIncome(Husband<T> &hobj, Wife<T> &wobj);

        public:
            Husband() = default;
            Husband(T new_salary): salary{new_salary} {}

        private:
            T salary;
        };

template<typename T>
        class Wife{
        friend void totalIncome(Husband<T> &hobj, Wife<T> &wobj);

        public:
        Wife() = default;
        Wife(T new_salary): salary{new_salary} {}

        private:
            T salary;
        };

template<typename T> void totalIncome(Husband<T> &hobj, Wife<T> &wobj)   __
{                                                                         |
    cout << "Total Income of Husband & Wife: ";                           |
    cout << hobj.salary + wobj.salary;                                    |
}                                                                         |
                                                                        ---
int main()
{
    Husband<int> h(40000);
    Wife<int> w(90000);

    totalIncome(h, w);

    return 0;
}
#包括
使用名称空间std;
模板类妻子;//模板的转发声明
模板
班夫{
朋友收入(丈夫和丈夫、妻子和妻子);
公众:
丈夫()=违约;
丈夫(新工资):工资{新工资}{
私人:
T工资;
};
模板
班主任{
朋友收入(丈夫和丈夫、妻子和妻子);
公众:
妻子()=默认;
妻子(新工资):工资{新工资}{
私人:
T工资;
};
模板无效总收入(丈夫和家庭主妇、妻子和家庭主妇)__
{                                                                         |

cout首先,让我们将其简化为一个再现问题的最小示例:

template<typename T>
        class Husband{
        friend void totalIncome(Husband<T> &);
        };

template<typename T> void totalIncome(Husband<T> &hobj)
{}

int main()
{
    Husband<int> h;
    totalIncome(h);
}
友元函数声明在最内部的封闭命名空间(包括在内)的周围作用域中查找已声明函数的名称(此处:
totalIncome
)。如果找到该名称的声明,则声明的实体将成为友元:

class Husband;
void totalIncome(Husband&);             // (A)

class Husband{
    friend void totalIncome(Husband&);  // befriends (A)
};
如果未找到名称声明,则在最内层的封闭命名空间中声明一个新函数:

class Husband{
    friend void totalIncome(Husband&);  // declares and befriends ::totalIncome
};

void totalIncome(Husband&);             // friend of class Husband
如果函数仅通过友元函数声明声明(并且在封闭的命名空间中没有后续声明),则只能通过依赖于参数的查找找到函数


在类模板中与函数交朋友 OP代码中的问题是涉及到一个类模板:

template<typename T>
        class Husband{
        friend void totalIncome(Husband<T> &);
        };
请注意,这是两个不相关的函数,非常类似于:

void totalIncome(int &);
void totalIncome(double &);

使用函数模板重载函数 您可以使用函数模板重载“普通”函数:

void totalIncome(Husband<int> &);    // (A)

template<typename T>
    void totalIncome(Husband<T> &);  // (B)
template<typename T>
        class Husband{
        template<typename U>
                friend void totalIncome(Husband<U> &);
        };

template<typename T> void totalIncome(Husband<T> &hobj)
{}

使用正向声明的解决方案:

template<typename T>
        class Husband;

template<typename T>
        void totalIncome(Husband<T> &);

template<typename T>
        class Husband{
        friend void totalIncome(Husband<T> &);
        };

template<typename T> void totalIncome(Husband<T> &hobj)
{}

在这个解决方案中,friend声明声明了一个函数模板,随后在类的定义后面的命名空间范围中的声明重新声明并定义了这个函数模板。函数模板的所有专门化都将被
丈夫
的所有实例化所友好de>friend void totalIncome(丈夫和hobj,妻子和wobj);
在全局范围内声明函数,但稍后您将使用相同的名称定义函数模板。函数模板不是函数,因此这两个实体不相同。将有两个函数声明(一个来自friend函数,一个来自函数模板专用化),重载解析选择未定义的友元函数。请尝试在友元声明之前声明函数模板。类似于:类似于:@dyp nope它们是不同的问题。无法通过查看这些问题推断解决方案。这些问题不是完全重复的,因此我没有关闭您的问题。参考答案但是,这三个问题的问题是相同的。在第一个环节中,罪魁祸首是
操作员*
,而在你的问题中,罪魁祸首是
总收入
。一个人是操作员这一事实在这里无关紧要。
void totalIncome(int &);
void totalIncome(double &);
void totalIncome(Husband<int> &);    // (A)

template<typename T>
    void totalIncome(Husband<T> &);  // (B)
void totalIncome<int>(Husband<int> &); // (C), instantiated from (B)
void totalIncome(Husband<int> &);       // (A)
void totalIncome<int>(Husband<int> &);  // (C)
template<typename T>
        class Husband{
        friend void totalIncome(Husband<T> &){
            // code here
        }
        };
template<typename T>
        class Husband;

template<typename T>
        void totalIncome(Husband<T> &);

template<typename T>
        class Husband{
        friend void totalIncome(Husband<T> &);
        };

template<typename T> void totalIncome(Husband<T> &hobj)
{}
template<typename T>
        class Husband{
        friend void totalIncome<T>(Husband<T> &);
        };
template<typename T>
        class Husband{
        template<typename U>
                friend void totalIncome(Husband<U> &);
        };

template<typename T> void totalIncome(Husband<T> &hobj)
{}