在命名空间外定义朋友模板方法

时间:2013-04-19 08:20:45

标签: c++ templates namespaces operators friend

我的代码具有以下基本结构:

namespace A{

    template<class T,unsigned DIM>
    class CMyTable{
        ...
            public:
            template<class T,unsigned DIM>
            friend std::ostream& operator<<(std::ostream& s, const CMyTable<T,DIM>& vec);
        }    

    };

}

最初的问题是让我的运营商&lt;&lt;在命名空间A之外。

我尝试了这个解决方案:How do I define friends in global namespace within another C++ namespace?

namespace A{

    template<class T,unsigned DIM>
    class CMyTable;
}

template<class T,unsigned DIM>
std::ostream& operator<<(std::ostream& s, const CMyTable<T,DIM>& vec);

namespace A{

    template<class T,unsigned DIM>
    class CMyTable{
        ...
            public:
            template<class T,unsigned DIM>
            friend std::ostream& ::operator<<(std::ostream& s, const CMyTable<T,DIM>& vec);
        }    

    };

}

template<class T,unsigned DIM>
std::ostream& operator<<(std::ostream& s, const CMyTable<T,DIM>& vec){
// [...]
}

我收到此错误:错误C2063:'operator&lt;&lt;' :不是类声明中的函数。

public:
template<class T,unsigned DIM>
friend std::ostream& ::operator<<(std::ostream& s, const CMyTable<T,DIM>& 

有没有人有任何想法?

感谢。

2 个答案:

答案 0 :(得分:0)

输出操作符实际上是类的接口,所以,从逻辑上讲,它应该在名称空间中,声明类,但是为了让你的代码有效,你可以使用

namespace A{

    template<class T,unsigned DIM>
    class CMyTable;
}

// friend is not correct here.
template<class T,unsigned DIM>
/*friend*/ std::ostream& operator<<(std::ostream& s, const A::CMyTable<T,DIM>& vec);

namespace A{

    template<class T,unsigned DIM>
    class CMyTable{
        ...
            public:
            // choose another names of template pars.
            // or use
            //friend std::ostream& (::operator << <>)(std::ostream& s,
            //const CMyTable<T, DIM>&);
            /*template<class T,unsigned DIM>*/
            template<class U, unsigned D>
            friend std::ostream& (::operator <<)(std::ostream&,
            const CMyTable<U,D>&);
        };
}

template<class T,unsigned DIM>
std::ostream& operator<<(std::ostream& s, const A::CMyTable<T,DIM>& vec){
// [...]
}

答案 1 :(得分:0)

如果您的ostream重载必须是friend需要访问受保护成员),那么将其内联定义,以便您可以使用传递给该类的模板参数。

namespace A{

    template<class T,unsigned DIM>
    class CMyTable{
        ...
        public:
        // template<class T,unsigned DIM>  // This will shadow otherwise
        friend std::ostream& operator<<(std::ostream& s, const CMyTable<T,DIM>& vec) {
        // [...]
        }
    };
}

否则完全从类和namesapce中删除它的声明,只是将它定义为模板化的重载。

请记住,如果它不需要访问私有或受保护的元素,则不必是朋友。

namespace A{
   template<class T,unsigned DIM>
   class CMyTable{
    ...
        public:
    };
}



template<class T,unsigned DIM>
std::ostream& operator<<(std::ostream& s, const A::CMyTable<T,DIM>& vec){
// [...]
}

第三个选项是让它保持友好,但在命名空间A中定义它

namespace A{

    template<class T,unsigned DIM>
    class CMyTable{
        public:
            int i;

        template<class V,unsigned E>
        friend std::ostream& operator<<(std::ostream& s, const CMyTable<V,E>& vec);
    };  

};
//
//

namespace A{

    template<class T,unsigned DIM>
    std::ostream& operator<<(std::ostream& s, const CMyTable<T,DIM>& vec) {
        s << vec.i;
    }

}