我有一个Value
类,它可以保存各种数据类型的值。
class Value
{
private:
union
{
int Integer;
double Real;
bool Boolean;
};
ValueTypes valType;
public:
Value();
Value(double Val);
Value(int Val);
Value(bool Val);
/* ... */
friend std::ostream& operator <<(std::ostream& stream, const Value& val);
}
我想重载<<
运算符,因此可以打印一个值,而无需调查其类型。
这是我目前的实施:
std::ostream &operator <<(std::ostream &os, const Value &val)
{
switch (val.valType)
{
case ValueTypes::Real:
os << val.Real;
break;
case ValueTypes::Integer:
os << val.Integer;
break;
case ValueTypes::Boolean:
os << (val.Boolean ? "True" : "False");
break;
}
return os;
}
首先,在使用g ++(CodeBlocks IDE,Ubuntu)进行编译时,实现会导致隐式转换为Value
。当值类型为Integer
或Real
时,os <<
语句会将其转换为Value
,然后再次调用ostream
重载(无限)递归),所以我最终得到了分段错误。
其次,在使用Visual C ++进行编译时,隐式转换已经消失,并且它打印的值很好(不会调用隐式构造函数)。
注意:
我希望保持隐式构造函数,因为它增强了可读性并简化了项目其他部分的维护。
此外,我发现了以下blog post,但未能调整我的代码,因此它将按照我的意愿执行(模板的使用有点超出了我目前对cpp语法的理解)。
如何在特定的ostream
重载功能中禁用隐式转换?
修改
启用-Wall
后,我在CodeBlocks中没有收到任何警告。
答案 0 :(得分:3)
您需要#include <ostream>
。没有它的原因是它没有用,因为那是实际定义std::ostream
的标题和所有有用的operator<<
函数。
它没有吓到并抱怨“std::ostream
”(或其他<<
运营商)没有定义的原因是因为前向声明。如果转发声明类型,则可以将其用作指针或引用(只要您不尝试进一步访问它)。 You can do some things with an incomplete type
您包含的其他标题可能会向前声明std::ostream
,但永远不会为它和所有<<
运算符提供完整的定义。至少在你的Ubuntu系统上。在其他系统上,其他标头可能包含<ostream>
或至少提供了<ostream>
所做的一些定义。您的operator<<
可能是编译器看到的唯一一个(因为您没有包含<ostream>
),并且因为它是编译器唯一知道的,所以它试图将它用于所有内容。
简而言之,在处理跨平台的东西时,人们应该迂腐地确定必要的内容(而不是依赖其他标题来包含与它们无关的内容)。