2011-03-03 52 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