C++模板类嵌套友元模板函数的问题
针对标题描述的问题,不同的C++编译器支持对其情况不同。以下介绍的问题示例,其中注释内容包含一些代码写法,在不同编译器上面编译链接都存在不同结果。
// 模板类型的定义!
// //作为友元函数情况,写法1:
针对标题描述的问题,不同的C++编译器支持对其情况不同。以下介绍的问题示例,其中注释内容包含一些代码写法,在不同编译器上面编译链接都存在不同结果。
PS. 该问题涉及C++语言特性,包括类模板,函数模板,operator操作符重载等。
以一个例子开始说明该问题。请注意代码的注释说明,如下:
// 事先声明模板函数类型
template <typename _TChar>
basic_istream<_TChar, char_traits<_TChar> >&
operator >> (basic_istream<_TChar, char_traits<_TChar> >& ins, commit_info_t<_TChar>& obj);
template <typename _TChar>
basic_ostream<_TChar, char_traits<_TChar> >&
operator << (basic_ostream<_TChar, char_traits<_TChar> >& outs, const commit_info_t<_TChar>& obj);
basic_istream<_TChar, char_traits<_TChar> >&
operator >> (basic_istream<_TChar, char_traits<_TChar> >& ins, commit_info_t<_TChar>& obj);
template <typename _TChar>
basic_ostream<_TChar, char_traits<_TChar> >&
operator << (basic_ostream<_TChar, char_traits<_TChar> >& outs, const commit_info_t<_TChar>& obj);
// 模板类型的定义!
template <typename _TChar>
struct commit_info_t
{
typedef basic_string<_TChar> TString;
TString* moudle_name;
TString* director_name;
//unsigned __int64 revision_num;
TString* revision_num;
TString* commit_time;
TString* ver_num;
TString* release_date;
TString* ver_info;
...
// //作为成员函数情况,可顺利编译通过,但是不能正常被流式调用如 fin >> obj; 只能这么调用obj.operator >> (fin); 看着怪怪的吧。
// basic_istream<_TChar, char_traits<_TChar> >& operator >> (basic_istream<_TChar, char_traits<_TChar> >& ins);
// basic_ostream<_TChar, char_traits<_TChar> >& operator << (basic_ostream<_TChar, char_traits<_TChar> >& outs);
struct commit_info_t
{
typedef basic_string<_TChar> TString;
TString* moudle_name;
TString* director_name;
//unsigned __int64 revision_num;
TString* revision_num;
TString* commit_time;
TString* ver_num;
TString* release_date;
TString* ver_info;
...
// //作为成员函数情况,可顺利编译通过,但是不能正常被流式调用如 fin >> obj; 只能这么调用obj.operator >> (fin); 看着怪怪的吧。
// basic_istream<_TChar, char_traits<_TChar> >& operator >> (basic_istream<_TChar, char_traits<_TChar> >& ins);
// basic_ostream<_TChar, char_traits<_TChar> >& operator << (basic_ostream<_TChar, char_traits<_TChar> >& outs);
// //作为友元函数情况,写法1:
// //在VS2008顺利编译链接通过。比较正常的用法!
// //在Codeblocks10.05不能编译通过,对应版本的GCC编译器不识别下面的语法。
// template <typename _TChar>
// friend basic_istream<_TChar, char_traits<_TChar> >& operator >>(basic_istream<_TChar, char_traits<_TChar> >& ins,\
// commit_info_t<_TChar>& obj);
// template <typename _TChar>
// friend basic_ostream<_TChar, char_traits<_TChar> >& operator <<(basic_ostream<_TChar, char_traits<_TChar> >& outs,\
// const commit_info_t<_TChar>& obj);
// //作为友元函数情况,写法2:
// //在Codeblocks10.05不能编译通过,对应版本的GCC编译器不识别下面的语法。
// template <typename _TChar>
// friend basic_istream<_TChar, char_traits<_TChar> >& operator >>(basic_istream<_TChar, char_traits<_TChar> >& ins,\
// commit_info_t<_TChar>& obj);
// template <typename _TChar>
// friend basic_ostream<_TChar, char_traits<_TChar> >& operator <<(basic_ostream<_TChar, char_traits<_TChar> >& outs,\
// const commit_info_t<_TChar>& obj);
// //作为友元函数情况,写法2:
// //在VS2008顺利编译链接通过。看看如下怪异的<> 用法吧!
// //同样,在Codeblocks10.05顺利编译链接通过。
// //同样,在Codeblocks10.05顺利编译链接通过。
friend basic_istream<_TChar, char_traits<_TChar> >& operator >> <>(basic_istream<_TChar, char_traits<_TChar> >& ins,\
commit_info_t<_TChar>& obj);
friend basic_ostream<_TChar, char_traits<_TChar> >& operator << <>(basic_ostream<_TChar, char_traits<_TChar> >& outs,\
const commit_info_t<_TChar>& obj);
// //作为友元函数情况,另一种写法3:
// //下面的模板函数声明,VS2008编译通过但链接不过,找不到其定义。
commit_info_t<_TChar>& obj);
friend basic_ostream<_TChar, char_traits<_TChar> >& operator << <>(basic_ostream<_TChar, char_traits<_TChar> >& outs,\
const commit_info_t<_TChar>& obj);
// //作为友元函数情况,另一种写法3:
// //下面的模板函数声明,VS2008编译通过但链接不过,找不到其定义。
// //在Codeblocks10.05不能编译通过。
// template <typename char_t>
// friend basic_istream<char_t, char_traits<char_t> >& operator >> (basic_istream<char_t, char_traits<char_t> >& ins,\
// commit_info_t<char_t>& obj);
// template <typename char_t>
// friend basic_ostream<char_t, char_traits<char_t> >& operator << (basic_ostream<char_t, char_traits<char_t> >& outs,\
// const commit_info_t<char_t>& obj);
// 是否还有其他更好的办法,有待继续探索 ...
...
}
...
// friend basic_istream<char_t, char_traits<char_t> >& operator >> (basic_istream<char_t, char_traits<char_t> >& ins,\
// commit_info_t<char_t>& obj);
// template <typename char_t>
// friend basic_ostream<char_t, char_traits<char_t> >& operator << (basic_ostream<char_t, char_traits<char_t> >& outs,\
// const commit_info_t<char_t>& obj);
// 是否还有其他更好的办法,有待继续探索 ...
...
}
...
// 友元函数定义!
template <typename _TChar>
basic_istream<_TChar, char_traits<_TChar> >& operator >> (basic_istream<_TChar, char_traits<_TChar> >& ins, \
commit_info_t<_TChar>& obj)
{
...
}
template <typename _TChar>
basic_ostream<_TChar, char_traits<_TChar> >& operator << (basic_ostream<_TChar, char_traits<_TChar> >& outs,\
const commit_info_t<_TChar>& obj)
{
...
}
template <typename _TChar>
basic_istream<_TChar, char_traits<_TChar> >& operator >> (basic_istream<_TChar, char_traits<_TChar> >& ins, \
commit_info_t<_TChar>& obj)
{
...
}
template <typename _TChar>
basic_ostream<_TChar, char_traits<_TChar> >& operator << (basic_ostream<_TChar, char_traits<_TChar> >& outs,\
const commit_info_t<_TChar>& obj)
{
...
}
小小总结:
作为C++的一个特性,针对模板类嵌套友元模板函数这种情况,支持情况依赖于不同编译器的支持情况。若代码设计涉及该情况,可能出现困扰的情况如编译器编译或链接不过。所以,建议尽量减少这样的代码设计,考虑是否可以借助其他实现方式规避,比如不定义模板类型或不定义友元模板函数等。
示例源码,可参考Github代码:
类模板之内声明友元模板函数和友元模板类型的相关知识,可以参见:
没有评论:
发表评论