1

ロギング コンテキストでは、ユーティリティ クラスの一時インスタンスを使用して出力を収集し、デストラクタを使用して収集した出力を破棄したいと考えています。たとえば、次のように標準出力に出力します。

名前付きの自動インスタンスと比較して、ユーティリティ インスタンスがインラインの匿名インスタンスとして構築されているかどうかに応じて、動作が異なることに気付きました。

名前付きインスタンスにより、期待される動作と出力が得られます。インライン インスタンスは、最初の挿入操作に問題があり、明らかに int への単純な変換を持つオペランドでのみ機能します。

これらの異なる方法で使用されるインスタンスの違いは何ですか?

#include <string>
#include <sstream>
#include <iostream>

class Util
{
public:
    std::ostringstream m_os;

    Util() {}
    ~Util() { std::cout << m_os.str() << std::endl;}
};



int main (void)
{
// ----------- Using temporary anonymous instance - 
    //  Output does not match expected, and the first insertion seems to
    //  only be able to handle instances that can be converted to int.

    // Following prints "97key=val", but expect "akey=val"
    (Util()).m_os << char('a') << std::string("key") << "=" << std::string("val");

    // Following prints "0x80491eakey=val", but expect "Plain old C string key=val"
    (Util()).m_os << "Plain old C string " << std::string("key") << "=" << std::string("val");

    // Following results in syntax error
    // error: no match for ‘operator<<’ in ‘Util().Util::m_os <<
    (Util()).m_os << std::string("key") << "=" << std::string("val");


// ----------- Using named instance - output matches expected

    // Block results in print "akey=val"
    {
        Util inst;
        inst.m_os  << char('a') << std::string("key") << "=" << std::string("val");
    }

    // Block results in print "Plain old C string key=val"
    {
        Util inst;
        inst.m_os  << "Plain old C string " << std::string("key") << "=" << std::string("val");
    }

    // Block results in print "key=val"
    {
        Util inst;
        inst.m_os  << std::string("key") << "=" << std::string("val");
    }

    return 0;
}
4

1 に答える 1

2

(Util())一時オブジェクトを作成します。その結果、(Util()).m_os一時的なオブジェクトでもあります。

operator<<メンバー関数としての定義がいくつかあり、独立した関数としての定義がいくつかあります。前者は一時オブジェクトに対して機能しますが、後者は機能しません。一時オブジェクトはストリームへの参照にバインドできないためです。コードを完全な例に単純化する:

#include <stdio.h>

struct stream
{
    stream& operator<<(int)
    { puts("operator<<(int)"); return *this; }
};

stream& operator<<(stream& s, char)
{ puts("operator<<(char)"); return s; }

struct streamwrapper
{
    stream s;
};

int main()
{
    streamwrapper w;
    w.s << 'a'; // outputs operator<<(char)

    streamwrapper().s << 'a'; // outputs operator<<(int)
}

予期したオーバーロードは利用できませんが、他のオーバーロードは利用できないため、ハード コンパイラ エラーが発生する代わりに、他のオーバーロードが使用されます。

于 2013-09-26T18:26:33.393 に答える