提问人:keinpop 提问时间:11/1/2023 更新时间:11/1/2023 访问量:85
问题在于使用模板编写运算符重载<<和>>
The problem is writing operator overloading << and >> using templates
问:
我有一类形状,它的工作原理是形状由点(x 和 y 坐标)组成。但是重载输入和输出运算符时,我遇到了一个可能作为错误的问题。
编译器是这样说的:
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;
}
答:
0赞
Some programmer dude
11/1/2023
#1
宣言
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);
另请阅读为什么模板只能在头文件中实现?
模板不能像这样真正拆分为单独的源文件和头文件。
评论
0赞
keinpop
11/1/2023
它没有帮助,我已经尝试过了,越来越多的警告出现。甚至还有一个错误:/usr/include/c++/11/ostream:750:5: error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
1赞
chris
11/1/2023
@keinpop,不同的错误并不意味着它没有帮助。我注意到您正在尝试输出 .std::pair
0赞
Some programmer dude
11/1/2023
@keinpop 您询问的错误消息非常明确地指出声明“声明了非模板函数”。friend
0赞
keinpop
11/1/2023
@Someprogrammerdude,如果我删除朋友,会出现其他错误,这无济于事
1赞
Remy Lebeau
11/1/2023
@Someprogrammerdude “模板不能像那样真正拆分为单独的源文件和头文件”——如果你更仔细地看,是'ing在最后,所以这是分离模板声明和定义的有效方法,只要不编译为它自己的翻译单元。figure.h
#include
figure.cpp
figure.cpp
0赞
Mooing Duck
11/1/2023
#2
问题是 ,但后来你把它定义为一个模板函数。解决方案是首先简单地将其声明为模板函数。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>
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)
0赞
Red.Wave
11/1/2023
#3
最简单的方法是内联友元函数。我们可以组合的另一件事是模板名称注入;即在模板中,您不需要模板参数列表,除非您引用具有不同参数集的另一个实例化:
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"};
您可以从这个简单的示例开始,并对其进行详细说明以获得最终结果。
评论