2011-03-03 112 views
7

考虑下面的代码:为什么写入临时流失败?

#include <sstream> 
#include <iostream> 

class Foo : public std::stringstream { 
public: 
    ~Foo() { std::cout << str(); } 
}; 

int main() 
{ 
    Foo foo; 
    foo << "Test1" << std::endl; 

    Foo() << "Test2" << std::endl; 

    return 0; 
} 

当我执行此,它给了我:

004177FC 
Test1 

我不明白,为什么第二个例子给我胡言乱语。临时应该活着,直到整个表达式被评估为止,为什么它不像第一个例子一样?

+0

编译器?平台? – CashCow 2011-03-03 11:33:18

+0

我不认为问题出在临时的一生。从汇编程序中,我可以看到它正在通过'char const *'takes操作符选择'std :: basic_ostream > :: operator <<(void const *)'。我无法解释它。我不明白为什么'void const *'接受运算符会比'char const *'接受运算符更好地匹配。 MSVC 2010打印这两个字符串,但我想这可能是因为一些扩展,而不是更符合。 – wilx 2011-03-03 12:16:09

+0

@wilx我已经回答了为什么可能发生这种情况:外部重载(不是类成员)和内部(类成员)确实会产生真正的差异。 – CashCow 2011-03-03 12:20:34

回答

7

我测试了它。

我可以猜测,operator<<不能结合临时到非const引用,所以任何外部定义的操作者< <功能不会对富临时工作,但任何类成员的将因此如果ostreamostringstream具有任何内部他们将会工作的operator<<成员。

因此,它可能是一个指针的重载是一个成员函数,而特殊的const char *是外部声明的。

对于更专业的过载,非临时可以绑定到非const引用。

如果你真的需要这一点,你可以测试一个包装

class Foo : 
{ 
    mutable std::ostringstream oss; 
public: 
    ~Foo() 
    { 
    std::cout << oss.str(); 
    } 

    template<typename T> 
    std::ostream& 
    operator<<(const T& t) const 
    { 
     return oss << t; 
    } 
}; 

和工程解决方法。第一个运算符< <将返回基础流。

我想这太,但它coredumped:

class Foo : std::ostringstream 
{ 
    Foo & nonconstref; 
public: 
    Foo() : nonconstref(*this) {} 
    ~Foo() 
    { 
    std::cout << str(); 
    } 

    template<typename T> 
    std::ostream& 
    operator<<(const T& t) const 
    { 
     return nonconstref << t; 
    } 
}; 

这也适用于:

class Foo : public std::ostringstream 
{ 
public: 
    Foo() {} 
    ~Foo() 
    { 
    std::cout << str(); 
    } 

    Foo& ncref() 
    { 
     return *this; 
    } 
}; 

int main() 
{ 
    Foo foo; 
    foo << "Test1" << std::endl; 

    Foo().ncref() << "Test2" << std::endl; 

} 
+2

在那里,做了,确认。我也想出了一个解决方法,就是执行std :: stringstream()。flush()<<“anything”;'。技巧是,'flush()'在'stringstream'上不做任何事情,但是通过引用返回invocant。注意,由于'operator <<'只返回'std :: ostream',所以你必须'static_cast'返回'stringstream'才能得到结果。 – 2011-03-03 11:52:04

+0

我得到了另一个不调用flush的解决方案,但是对于stringstream flush是一个no-op,所以在这种情况下起作用。 – CashCow 2011-03-03 12:19:33

+0

这是一个讨厌的问题,感谢您的解释。你的第一个解决方案不是一种选择,因为'operator <<'的模板不适用于'std :: endl' - 这就是我尝试使用继承的原因。我想我会用最后的解决方案。 – 2011-03-03 14:09:02