【发布时间】:2015-03-13 04:57:02
【问题描述】:
我正在编写一个重载 > 运算符的类,类似于 std::istream 和 std::ostream。前几个功能按预期工作。但是,我想在我自己的类中使用其他 std::*stream 类进行格式化,这会导致一个有趣的,我会说,“递归”编译器问题:
class SmartStream
{
public:
template <typename F> friend F &operator << (F &in, float f)
{
in.type ("f");
in.m_buf.str ("");
in.m_buf << f; // This causes a 'recursive' compile call
in.add (in.m_buf.str ());
return in;
}
protected:
std::ostringstream m_buf;
void type(const std::string &_type) {};
void add(const std::string &) {};
};
实际的错误很长,但开头是这样的:
rec_stream.cpp: In instantiation of 'F& operator<<(F&, float) [with F = std::basic_ostringstream<char>]':
rec_stream.cpp:14:18: required from 'F& operator<<(F&, float) [with F = ExtraStream]'
rec_stream.cpp:60:11: required from here
rec_stream.cpp:12:9: error: 'class std::basic_ostringstream<char>' has no member named 'type'
in.type ("f");
^
显然,编译器将相同的重载 m_buf 变量,但当然它没有 type() 和 add() 函数。在阅读了this question 的答案后,这有点道理,但没有提供解决方案。
在你说之前不,在 SmartStream 中使用它:
class SmartStream
{
....
SmartStream &operator << (float f)
{
type("f");
m_buf.str ("");
m_buf << f; // Ambiguous overload
add( m_buf.str ());
return *this;
}
};
有两个问题。首先,如代码中所述,这会触发模棱两可的重载。其次,考虑以下几点:
class ExtraStream: public SmartStream
{
public:
template <typename F> friend F &operator << (F &in, struct tm t)
{
in.type ("tm");
in.m_buf.str ("");
in.m_buf << t.tm_hour; // Ambiguous overload
in.add (in.m_buf.str ());
return in;
}
};
确实,我正在扩展 SmartStream 以使用该类中布置的机制来处理自定义类型。使用非朋友运算符将不允许我这样做:
ExtraStream es;
struct tm t1, t2;
float f1, f2;
es << f1 << t1 << f2 << t2; // works
因为<< (float) 之后的返回类型是SmartStream,它不知道如何处理struct tms。
我的问题:
有没有办法说服编译器(gcc 4.8.2)对 std::ostringstream 使用'base' in.m_buf << f; 的代码移动到 SmartStream 中的非模板函数,但没有任何帮助。
另外,为什么它只在模板运算符
【问题讨论】:
-
我只看了你的代码,但你试过
in.m_buf.ostrongstream::operator<<(f)吗?请注意,您需要一个using指令,因为成员访问权限不能是命名空间限定的。 -
你的模板朋友太笼统了,他们什么都拿,在那里更具体。
-
@dyp:很有趣。 gist.github.com/sharth/6b09bd9e5aca4585370c 使用 clang++ 编译良好,但使用 g++ 4.9.0 编译失败...
-
@5gon12eder:好吧,
in.m_buf::ostringstream::operator << f和in.m_buf.ostringstream::operator << f都不起作用。除非您可以指定正确的using指令,否则using std::ostringstream::operator<<将不起作用(我不确定这是否可行,因为它是一个运算符,而不是一个函数)