请教关于c++中模板类中友元函数的定义和使用。

MichaelMicheal 2015-11-30 11:32:35
这个类的头文件
//---test.h

#ifndef test_h_
#define test_h_
#include <iostream>
using namespace std;

template <class T>
class Test
{
private:
T x;
public:
Test (T x_): x(x_) {}
friend void display(Test<T> &t);
};

template <class T>
void display(Test<T> &t)
{
cout << t.x << endl;
}


#endif // test_h_

这时main函数
// ----main.cpp
#include <iostream>
#include "test.h"

using namespace std;

int main()
{
// cout << "Hello world!" << endl;
Test<int> t(20);
display(t);
return 0;
}


这是编译信息
||=== Build: Debug in fucking_test (compiler: GNU GCC Compiler) ===|
D:\C++\DataStructure\linear_list\fucking_test\test.h|13|warning: friend declaration 'void display(Test<T>&)' declares a non-template function [-Wnon-template-friend]|
D:\C++\DataStructure\linear_list\fucking_test\test.h|13|note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here) |
obj\Debug\main.o||In function `main':|
D:\C++\DataStructure\linear_list\fucking_test\main.cpp|10|undefined reference to `display(Test<int>&)'|
||=== Build failed: 1 error(s), 1 warning(s) (0 minute(s), 0 second(s)) ===|
||=== Run: Debug in fucking_test (compiler: GNU GCC Compiler) ===|

不知道编译器在warning什么毛线。
还有为嘛主函数调用友元函数会提示函数并没有定义引用?
我试着把主函数的友元函数调用写成这样Test<int>display(t);但是发现只是执行类里面的函数声明,似乎与类外那个函数定义木有关系。
求大神解答。
...全文
760 12 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
Esdeath_yzh 2017-05-11
  • 打赏
  • 举报
回复
楼主怎么解决的?
D41D8CD98F 2015-12-01
  • 打赏
  • 举报
回复
friend void display(Test<T> &t); ↑ 这不是函数模板 template <class T> void display(Test<T> &t) { cout << t.x << endl; } ↑ 这是函数模板 本质上不是同一类东西,自然不可能后者是前者的定义 一个可行的解决方法(也是你的编译器所指出的方法)是对头文件做两处改动:
//---test.h
 
#ifndef test_h_
#define test_h_
#include <iostream>
using namespace std;
 
// 改动一:增加函数模板的声明——而这又需要先声明类模板
template <class T> class Test;
template <class T>
void display(Test<T> &t);

template <class T>
class Test
{
private:
    T x;
public:
    Test (T x_): x(x_) {}
    friend void display<>(Test<T> &t);
// 改动二:在函数名后面加上<>,指明它是之前声明的函数模板 的实例
};
 
template <class T>
void display(Test<T> &t)
{
    cout << t.x << endl;
}
 
 
#endif // test_h_
MichaelMicheal 2015-12-01
  • 打赏
  • 举报
回复
引用 3 楼 fefe82 的回复:
因为你使用了一个非模板的普通函数作为模板类的友元,而这个普通函数的参数有一依赖于模板参数的着。 这就意味着,对模板类的每一个 instantiation ,你必须单独定义一个函数。这通常不是期望的结果。 比如你的程序中,你的函数模板 display 就并不是你的类的友元。(该类中定义的友元是一个普通函数,不是函数模板,也不是函数模板的特化)
谢谢你,不过好抽象啊。 我看了primer plus大概知道什么意思,但是那个书就算书中的源代码也是一堆bug,无语了。。。
MichaelMicheal 2015-12-01
  • 打赏
  • 举报
回复
引用 1 楼 Jammg 的回复:
友元函数不能当做声明,编译器报错应该是在class被编译是看不到display的声明,你前置声明一下,或者其他办法应该能解决
谢谢你。 感觉cpp语法真坑。。。
MichaelMicheal 2015-12-01
  • 打赏
  • 举报
回复
引用 2 楼 D41D8CD98F 的回复:
friend void display(Test<T> &t); ↑ 这不是函数模板 template <class T> void display(Test<T> &t) { cout << t.x << endl; } ↑ 这是函数模板 本质上不是同一类东西,自然不可能后者是前者的定义 一个可行的解决方法(也是你的编译器所指出的方法)是对头文件做两处改动:
//---test.h
 
#ifndef test_h_
#define test_h_
#include <iostream>
using namespace std;
 
// 改动一:增加函数模板的声明——而这又需要先声明类模板
template <class T> class Test;
template <class T>
void display(Test<T> &t);

template <class T>
class Test
{
private:
    T x;
public:
    Test (T x_): x(x_) {}
    friend void display<>(Test<T> &t);
// 改动二:在函数名后面加上<>,指明它是之前声明的函数模板 的实例
};
 
template <class T>
void display(Test<T> &t)
{
    cout << t.x << endl;
}
 
 
#endif // test_h_
你好,先谢谢你的回答。我试了改了一下,发现主函数输出nothing,什么都没有。于是试着在头文件那个函数这么添加:
template <class T>
void display(Test<T> &t)
{
    cout << t.x << endl;
    cout << "display." << endl;  // 看看有木有调用到这个函数
}
发现并没有调用这个函数,这个函数与模板类中定义的友元函数并不是关联的,郁闷中
fefe82 2015-12-01
  • 打赏
  • 举报
回复
因为你使用了一个非模板的普通函数作为模板类的友元,而这个普通函数的参数有一依赖于模板参数的着。 这就意味着,对模板类的每一个 instantiation ,你必须单独定义一个函数。这通常不是期望的结果。 比如你的程序中,你的函数模板 display 就并不是你的类的友元。(该类中定义的友元是一个普通函数,不是函数模板,也不是函数模板的特化)
MichaelMicheal 2015-12-01
  • 打赏
  • 举报
回复
引用 9 楼 whhlpo 的回复:
没有必要前置声明。 好好理解下 D41D8CD98F 的说明
谢谢你,这个坑终于解决了。
MichaelMicheal 2015-12-01
  • 打赏
  • 举报
回复
引用 2 楼 D41D8CD98F 的回复:
friend void display(Test<T> &t); ↑ 这不是函数模板 template <class T> void display(Test<T> &t) { cout << t.x << endl; } ↑ 这是函数模板 本质上不是同一类东西,自然不可能后者是前者的定义 一个可行的解决方法(也是你的编译器所指出的方法)是对头文件做两处改动:
//---test.h
 
#ifndef test_h_
#define test_h_
#include <iostream>
using namespace std;
 
// 改动一:增加函数模板的声明——而这又需要先声明类模板
template <class T> class Test;
template <class T>
void display(Test<T> &t);

template <class T>
class Test
{
private:
    T x;
public:
    Test (T x_): x(x_) {}
    friend void display<>(Test<T> &t);
// 改动二:在函数名后面加上<>,指明它是之前声明的函数模板 的实例
};
 
template <class T>
void display(Test<T> &t)
{
    cout << t.x << endl;
}
 
 
#endif // test_h_
谢谢,我知道问题在哪里了。
Huppert 2015-12-01
  • 打赏
  • 举报
回复
没有必要前置声明。 好好理解下 D41D8CD98F 的说明
Huppert 2015-12-01
  • 打赏
  • 举报
回复
#include <iostream>
using namespace std;


template <class T>
class Test
{
private:
	T x;
public:
	Test (T x_): x(x_) {}

	template <class Q>
	friend void display(Test<Q> &t);
};

template <class T>
void display(Test<T> &t)
{
	cout << t.x << endl;
}


int main()
{
	// cout << "Hello world!" << endl;
	Test<int> t(20);
	display(t);
	return 0;
}
Huppert 2015-12-01
  • 打赏
  • 举报
回复
#include <iostream>
using namespace std;

// 改动一:增加函数模板的声明——而这又需要先声明类模板
template <class T> class Test;
template <class T>
void display(Test<T> &t);

template <class T>
class Test
{
private:
	T x;
public:
	Test (T x_): x(x_) {}

	template <class Q>
	friend void display<>(Test<Q> &t);
	// 改动二:在函数名后面加上<>,指明它是之前声明的函数模板 的实例
};

template <class T>
void display(Test<T> &t)
{
	cout << t.x << endl;
}


int main()
{
	// cout << "Hello world!" << endl;
	Test<int> t(20);
	display(t);
	return 0;
}
weilin.jiang 2015-11-30
  • 打赏
  • 举报
回复
友元函数不能当做声明,编译器报错应该是在class被编译是看不到display的声明,你前置声明一下,或者其他办法应该能解决
目录 1. 简介 怎样使用本教程 2. C++基础 Basics of C++ 1. C++程序结构 Structure of a program 2. 变量和数据类型 Variables and Data types 3. 常量 Constants 4. 操作符/运算符 Operators 5. 控制台交互 Communication through console 3. 控制结构和函数 Control structures and Functions 1. 控制结构 Control Structures 2. 函数I Functions I 3. 函数II Functions II 4. 高级数据类型 Advanced Data 1. 数组 Arrays 2. 字符序列 Character Sequences 3. 指针 Pointers 4. 动态内存分配 Dynamic memory 5. 数据结构 Data Structures 6. 自定义数据类型 User defined data types 5. 面向对象编程 Object-oriented Programming 1. 类,构造函数和析构函数,类的指针 Classes. Constructors and Destructors. Pointers to classes. 2. 操作符重载,this,静态成员 Overloading Operators. this. Static members 3. 类之间的关系 Relationships between classes: friend. Inheritance 4. 虚拟成员,抽象,多态 Virtual Members. Abstraction. Polymorphism 6. C++高级 Advanced concepts 1. 模板 Templates 2. 名空间 Namespaces 3. 出错处理 Exception handling 4. 类型转换高级 Advacned Class Type-casting 5. 预处理指令 Preprocessor Directives 7. C++ 标准函数库 C++ Standard Library 1. 文件的输入输出 Input/Output with files C++基础教程简介 怎样使用本教程 读者范围 本教程面向所有希望学习C++语言的读者。如果读者有其他编程语言背景或计算机相关基本知识可以帮助更好的理解教程内容,但这并非必须条件。 对于C语言熟悉的读者可将前三章(1.1 到 3.4)当作复习,因为这部分内容主要介绍C++的C部分。不过某些C++的语法与C还是有些差别,所以建议还是快速的读一下这部分。 第四章讲述面向对象编程。 第五章主要介绍ANSI-C++标准的新增的功能。 本教程结构 教程共分6章,每章分若干小节。你可以直接从主目录进入任意小节,并循每页底部的链接向后浏览。 很多小节含有一页例题介绍该章节主要知识点的使用。建议在进入下一章学习之前最好先阅读这些例题,理解每行代码。 学习和练习一种编程语言的最好办法是自己修改书例题程序,设法在程序增加新的功能。不要不敢修改这些例题程序,这正是学习的方法。 兼容性备注 ANSI-C++标准近几年来被接受为国际标准。尽管C++语言从二十世纪80年代即存在,ANSI-C++在1997年才被发表,2003年又被修订过。因此很多编译器不支持ANSI-C++的部分新功能,特别是那些在此标准发表前即被发布的编译器。 在本教程,那些ANSI-C++新增的而老一代C++编译器大多不支持概念将备用如下标志标出: ANSI C++新增的概念 同样对于C和C++在实现上有明显不同的概念,将备用如下标志标出: C 与 C++不同的地方 编译器 本教程所有例题程序均为console程序(控制台程序)。此类程序以文本形式与用户交换信息,显示结果。 所有C++编译器均支持console程序的编译。要了解更多关于如何编译的说明,请查询你的编译器用户使用手册。 C++编译器和开发环境推荐 很多读者询问编译器和开发环境的问题。除了常用的商用收费的MS Visual Studio, VC++,Borland C++等工具外,还有很多免费的工具也是很好用的。这里推荐两种免费的C++开发软件: 1、Eclipse的CDT开发工具,官方网站在http://www.eclipse.org/cdt/ 2、开源工具Dev-C++和wxDev-C++

65,196

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧