为啥 g++ 需要模板类及其友元函数的定义?
Posted
技术标签:
【中文标题】为啥 g++ 需要模板类及其友元函数的定义?【英文标题】:why does g++ need both definitions of template class and its friend function?为什么 g++ 需要模板类及其友元函数的定义? 【发布时间】:2017-10-28 06:19:55 【问题描述】:我想为模板类写一个友元函数。 在视觉工作室,我可以忽略预定义。 但在 g++ 中,它是强制性的。 为什么?
#include <iostream>
using namespace std;
// g++ needs, vs do not needs
template <class T>
class A;
template <class T>
ostream & operator<<(ostream & c, const A<T> & v);
//- end of g++ needs
template <class T>
class A
T _v;
public:
A()
A(T v) : _v(v)
friend ostream & operator<<<T>(ostream & c, const A<T> & v);
;
template <class T>
ostream & operator<<(ostream & c, const A<T> & v)
c << v._v; return c;
【问题讨论】:
我最好的猜测是 VisualStudio “帮助”你比 g++ 多一点,只是为你添加它。具有讽刺意味的是,g++ 似乎为您提供了更好的编译错误描述。我所说的“帮助”是指当我在代码中输入File.txt
时,VS 打开了 file.txt
,但 g++ 说文件不存在并且无法打开。
在 g++ 中,friend
函数声明(或定义?)需要原型。要制作原型,您又需要模板类的前向声明。在 g++ 中学习过一次后,我想知道这些天我的代码在 VS without 中是否可以工作(但我没有深入挖掘。)现在,我很清楚了。 (感谢您的提问。)
@BrianW 我相信,您提到的关于file.txt
与File.txt
的示例只是操作系统问题。在 Windows 上,文件名通常不区分大小写。 (如果应用程序不使用系统函数,它可能会破坏它。)当然,在 Linux 上,文件名总是区分大小写的(但是,如果不使用系统函数,应用程序可能会破坏它)。但是,总的来说,我同意您的看法:VS 关于 C++ 标准要宽松得多(方便?)。当我们将应用程序移植到我们在 Windows/VS 中开发的 Linux/g++ 时,我总是会遇到这个问题(尽管我们总是尝试制作可移植的代码)。
好点@Scheff,我没有考虑 Windows 与 Linux 的事情,并认为这只是 IDE。
@YunfeiDuan 请不要发布“谢谢”cmets。如果您想说“谢谢”,请为答案投票。 (这可以让作者获得 10 点声誉,一定会受到欢迎。)请不要忘记 accept 您认为解决问题的答案(作者 +15)。
【参考方案1】:
因为
friend ostream & operator<<<T>(ostream & c, const A<T> & v);
是
的特化template <class T>
ostream & operator<<(ostream & c, const A<T> & v);
你需要先声明,然后
A<T>
部分意味着你必须在操作符声明之前声明它
template <class T>
class A;
所以 VS 可能是错误的C++14
14.5.4 Friends [temp.friend]
举个例子
template<class T> class task;
template<class T> task<T>* preempt(task<T>*);
template<class T> class task
friend void next_time();
friend void process(task<T>*);
friend task<T>* preempt<T>(task<T>*);
template<class C> friend int func(C);
friend class task<int>;
template<class P> friend class frd;
;
您的示例适合第三个朋友声明。
【讨论】:
【参考方案2】:MSVC 模板代码被彻底破坏。在过去的几年里,他们一直在重建它,但它仍然包含你所观察到的怪癖。这是因为它被构建为几乎像宏一样,而不是 C++ 标准所要求的。
在 gcc 中,您可以通过在类的主体中内联定义 <<
运算符来取消前向声明:
friend std::ostream& operator<<(std::ostream& c, const A& v)
c << v._v;
return c;
这样做的好处是<<
不再是template
,而是为模板A
的每个实例创建的不同的非模板。在某些情况下,这往往效果更好。
【讨论】:
以上是关于为啥 g++ 需要模板类及其友元函数的定义?的主要内容,如果未能解决你的问题,请参考以下文章
C++ Primer 5th笔记(chap 16 模板和泛型编程)类模板和友元