请教关于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);但是发现只是执行类里面的函数声明,似乎与类外那个函数定义木有关系。
求大神解答。
...全文
739 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的声明,你前置声明一下,或者其他办法应该能解决

65,184

社区成员

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

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