编译器是这么说的:
In file included from main.cpp:1:
./header/figure.h:17:82: warning: friend declaration ‘std::ostream& operator<<(std::ostream&, const Figure<T>&)’ declares a non-template function [-Wnon-template-friend]
17 | friend std::ostream & operator<<(std::ostream & stream, const Figure<T> & fig);
| ^
./header/figure.h:17:82: note: (if this is not what you intended, make sure the function template has already been declared and add ‘<>’ after the function name here)
./header/figure.h:18:76: warning: friend declaration ‘std::istream& operator>>(std::istream&, Figure<T>&)’ declares a non-template function [-Wnon-template-friend]
18 | friend std::istream & operator>>(std::istream & stream, Figure<T> & fig);
| ^
/usr/bin/ld: /tmp/ccVeFfI2.o: в функции «main»:
main.cpp:(.text+0xdb): неопределённая ссылка на «operator<<(std::ostream&, Figure<double> const&)»
/usr/bin/ld: main.cpp:(.text+0xf1): неопределённая ссылка на «operator>>(std::istream&, Figure<double>&)»
collect2: error: ld returned 1 exit status
figure.h
#pragma once
#include <ostream>
#include "./dynamicArray.h"
template <class T>
class Figure
{
public:
Figure();
Figure(const DArray<std::pair<T, T>> & points);
Figure(const std::initializer_list<std::pair<T, T>> & coord);
~Figure() noexcept;
friend std::ostream & operator<<(std::ostream & stream, const Figure<T> & fig);
friend std::istream & operator>>(std::istream & stream, Figure<T> & fig);
protected:
DArray<std::pair<T, T>> _points;
std::string _name = "unnamed";
};
#include "../src/figure.cpp"
figure.cpp
#include "../header/figure.h"
template <class T>
Figure<T>::Figure() :
_points() {}
template <class T>
Figure<T>::Figure(const DArray<std::pair<T, T>> & points) :
_points(points) {}
template <class T>
Figure<T>::Figure(const std::initializer_list<std::pair<T, T>> & coord) :
_points(coord) {}
template <class T>
Figure<T>::~Figure() noexcept
{
}
template <class T>
std::ostream & operator<<(std::ostream & stream, const Figure<T> & fig)
{
size_t size = fig._points.getSize();
if (size == 0) {
return stream << 0;
}
for (size_t i = 0; i < size; ++i) {
stream << "Point " << i + 1 << "| ";
stream << fig._points[i];
}
return stream;
}
template <class T>
std::istream & operator>>(std::istream & stream, Figure<T> & fig)
{
std::pair<T, T> tmp;
std::cout << "Enter Ox: ";
stream >> tmp.first;
std::cout << "Enter Ox: ";
stream >> tmp.second;
fig._points.pushBack(tmp);
return stream;
}
friend std::ostream & operator<<(std::ostream & stream, const Figure<T> & fig);
是不是模板声明。但是
template <class T>
std::ostream & operator<<(std::ostream & stream, const Figure<T> & fig)
是一个模板。
您需要从一开始就将函数声明为模板:
template<typename U>
friend std::ostream & operator<<(std::ostream & stream, const Figure<U> & fig);
friend declaration ‘std::ostream& operator<<(std::ostream&, const Figure<T>&)’ declares a non-template function
,但是后来你把它定义为模板函数。解决方案是首先将其声明为模板函数。
template <class T>
friend std::ostream & operator<<(std::ostream & stream, const Figure<T> & fig);
template <class T>
friend std::istream & operator>>(std::istream & stream, Figure<T> & fig);
对于这些重载,声明 Figure<T>
与every
T
交友感觉有点奇怪,但这是简单的解决方案。“更正确”的解决方案稍微棘手一些。语法超出了我的想象,可能有点错误,但应该是这样的
//declare the class as existing as a template type.
template <class T>
class Figure;
//declare the function as existing as a template function.
template <class T>
std::ostream & operator<<(std::ostream & stream, const Figure<T> & fig);
//define the class
template<class T>
class Figure
{
public:
....
//now you can friend the specific instantiations
friend std::ostream & operator<<(std::ostream & stream, const Figure<T> & fig);
friend std::istream & operator>>(std::istream & stream, Figure<T> & fig);
或者语法可能是 friend std::ostream & operator<< <T>(std::ostream & stream, const Figure<T> & fig)
之类的。我不确定。
模板名称注入;即在模板内部,您不需要模板参数列表,除非您引用具有不同参数集的另一个实例化:
template<typename T>
struct test{
T val;
friend auto& operator <<
(std::ostream& os, test const& x){
return os << "value=" << x.val << "\n";
};
};
std::cout << test<int>{1} << test<std::string>{"hello"};
您可以从这个简单的示例开始,并对其进行详细说明以获得最终结果。