2012年3月7日星期三

C++模板类嵌套友元模板函数的问题


C++模板类嵌套友元模板函数的问题

针对标题描述的问题,不同的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);

// 模板类型的定义!

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);


//  //作为友元函数情况,
写法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:
//  //在VS2008顺利编译链接通过。看看如下怪异的<> 用法吧!
//  //同样,在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编译通过但链接不过,找不到其定义。
//  //在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);

    // 是否还有其他更好的办法,有待继续探索 ...

    ...
}

...
// 友元函数定义!
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代码:

类模板之内声明友元模板函数和友元模板类型的相关知识,可以参见:

没有评论:

发表评论