2008-11-14 37 views
5

ben amacının bu yapabilmek için bir günlük sınıf yazıyorumoperatörü << o çekmek veya dönmez ostream aşırı Nasıl

Orijinal Soru: Şu anda

// thread one 
Logger() << "Some string" << std::ios::hex << 45; 
// thread two 
Logger() << L"Some wide string" << std::endl; 

: Bu sınıfa hakkında

#pragma once; 
#include <ostream>  
class Logger 
{ 
public: 
    Logger(); 
    ~Logger(); 

    std::ostream* out_stream; 
}; 

template <typename T> 
Logger& operator<< (Logger& logger, T thing) { 
    *logger.out_stream << thing; 
    return logger; 
} 

Bazı notlar: my Kaydedici başlığı şuna benzer

  1. Çapraz platform uyumluluğu sorun değil.
  2. Logger.cpp'nin içinde "gerçek" ostream oluşturmaya özen gösteren bir singleton sınıfı var.
  3. Logger yapıcısı ve deconstructor, tekil için gerekli kilitleme işlemini gerçekleştirir.

    • nasıl operatörü < < fonksiyon yüzden özel olarak out_stream ayarlayabileceğiniz bir arkadaş veya üye yapabilirim:

Üç sorunları var?

  • İşleçler için işleç < < işlevini nasıl yapabilirim?
  • Bir uzmanlık alanını nasıl ekleyebilirim? T eğer bir WCHAR * veya std :: wstring ise onu out_stream öğesine geçirmeden önce char * veya std :: string olarak döndürecek? (. Ben benim durumumda bir sorun değildir, yüksek unicode karakterleri Losing dönüşüm yapabilirsiniz.) Cevaplar öğrenilen şeylerin
  • Özeti: sonra arkadaşı yerine ÖNCE

    • koyun şablonu.
    • std :: ios :: hex bir manipülatör değildir. std :: hex bir manipülatördür.

    Bitiş Sonucu (... üç noktayla) burayı printf yol yapmak ve çoklu parametre yöntemini kullanmayın neden

    #pragma once 
    #include <ostream> 
    #include <string> 
    
    std::string ConvertWstringToString(std::wstring wstr); 
    
    class Logger 
    { 
    public: 
        Logger(); 
        ~Logger(); 
    
        template <typename T> 
        Logger& operator<< (T data) { 
         *out << data; 
         return *this; 
        } 
        Logger& operator<< (std::wstring data) { 
         return *this << ConvertWstringToString(data); 
        } 
        Logger& operator<< (const wchar_t* data) { 
         std::wstring str(data); 
         return *this << str; 
        } 
    
    private: 
        std::ostream* out; 
    }; 
    
    +0

    Endresult'unuz yanlış. sınıf kapsamındaki uzmanlıklara izin verilmez :) sadece onları aşırı yüklemek (şablonu <> parça atlamak) Aksi halde (o zaman normal operatör işlevleri) artık arkadaş olmadığı için Adem'in cevabında (ad alanı kapsamında uzmanlaşır) gereklidir. –

    +0

    İlginç bir şekilde, onlarla orada çalıştı. Ancak, sadece doğru olmak gerekirse, onları yine de kaldırdım. Teşekkürler! –

    cevap

    7

    arkadaş çalışacak olursa sınıfın çevresindeki ad alanında operatörü tanımlayacak ve yalnızca operatör aşırı yüklenme çözünürlüğüne (operatör < < < ... sözdizimi kullanılarak elle kalibre edilemez) görülebilen tanım:

    class Logger 
    { 
    public: 
        Logger(); 
        ~Logger(); 
    
        std::ostream* out_stream; 
    
        template <typename T> 
        friend Logger& operator<< (Logger& logger, T thing) { 
         *logger.out_stream << thing; 
         return logger; 
        } 
    
        /* special treatment for std::wstring. just overload the operator! No need 
        * to specialize it. */ 
        friend Logger& operator<< (Logger& logger, const std::wstring & wstr) { 
         /* do something here */ 
        } 
    
    }; 
    

    alternatif olduğu gibi kodunuzu saklayıp yalnızca operatöre < < şablonu arkadaş yapmak, kendi sınıf tanımının içine bu satırı ekleyin:

    manipülatör sorun için
    template <typename T> 
    friend Logger& operator<< (Logger& logger, T thing); 
    

    , ben sadece verecek koduma yazdığım bir süre önce yazmam:

    #include <iostream> 
    #include <cstdlib> 
    using namespace std; 
    
    template<typename Char, typename Traits = char_traits<Char> > 
    struct logger{ 
        typedef std::basic_ostream<Char, Traits> ostream_type; 
        typedef ostream_type& (*manip_type)(ostream_type&); 
        logger(ostream_type& os):os(os){} 
        logger &operator<<(manip_type pfn) { 
         if(pfn == static_cast<manip_type>(std::endl)) { 
          time_t t = time(0); 
          os << " --- " << ctime(&t) << pfn; 
         } else 
          os << pfn; 
         return *this; 
        } 
        template<typename T> 
        logger &operator<<(T const& t) { 
         os << t; 
         return *this; 
        } 
    private:   
        ostream_type & os; 
    }; 
    
    namespace { logger<char> clogged(cout); } 
    int main() { clogged << "something with log functionality" << std::endl; } 
    

    };

    Bunun std :: hex olduğunu, ancak std :: ios :: hex olduğunu unutmayın. İkincisi, akışların setf işlevi için bir manipülatör bayrağı olarak kullanılır. Örneğiniz için, manipülatörlerin özel bir işleminin gerekli olmadığını unutmayın. Std :: endl'in yukarıdaki özel işlemi sadece std :: endl kullanıldığında ek olarak zaman akışı yaptığım için gereklidir. Bir şablon kullanarak

    +0

    Argh! Bunu yaptığımda günlüğüne 204845 aldığıma şaşırmadım. Manipülatörler gibi çalışır gibi görünüyor. Teşekkürler! –

    0

    . Bu hala size formüle etme gücü verir ve < <'u kullanırken olduğu gibi dağınık hale getirmez. Örneğin

    :

    Logger("This is my log msg %0X", 45); 
    

    iki saniye Dayan ve kötü sizin için bir kod örneği yukarı çekin.

    Düzenleme:

    void Logger(const char* format, ...) 
    { 
        char szMsg[3000]; 
    
        va_list args; 
        va_start(args, format); 
        vsnprintf(szMsg, sizeof(szMsg) - 1, format, args); 
        va_end(args); 
    
        // code to print szMsg to a file or whatever here 
    } 
    

    siz) tek başına bir fonksiyonu logger operatörü (aşılmasına neden değil bir sınıf olarak kullanmak istiyorum ve sadece aynı kullanabilirsiniz

    +0

    En mükemmel öneri! << formatını kullanmak istediğim iki neden var. Birincisi, ben '' nin birlikte zincirleme okunabilirliğini tercih ediyorum. Diğeri ise çok sayıda tamponun yaratılmasını önlemek istemem. –

    +0

    C++ kodunda varargs yöntemini kullanmamanın birtakım nedenleri vardır, özellikle de tip güvenliğini kaldırır, arayan/aranan kişi arasında sıkı bir bağlantı kurar ve UDT'lerin tanımlanmamış davranışları (hala izin verilir). – twokats

    +0

    Yararlı bilgi. Asla C++ – Lodle

    2

    bunu yapmak için doğru bir yoldur, ancak sadece şablon, başlık dosyası (logger.h, ya da her ne denir) de uygulama dosyasında değil emin olmak için (logger.cpp) sahip . Bu, std::ostream ile tanımlanan operator << olan her tür için otomatik olarak çalışır. Ayrıca, otomatik olarak akış manipülatör nesneleri ile çalışacak - bunlar gerçekten sadece std::ostream parametresini kullanan işlevlerdir ve operator << sadece ostream'daki işlevi çağırır. aşağıdaki gibi

    Bir arkadaşı fonksiyonu operator << yapabilirsiniz:

    template <typename T> friend Logger& operator<< (Logger& logger, T thing); 
    

    Uzmanlık kolaydır - sadece (başlık dosyasında, tekrar) şablon uzmanlık kullanın:

    template <typename T> 
    Logger& operator<< (Logger& logger, T thing) { 
        *logger.out_stream << thing; 
        return logger; 
    } 
    
    // Template specialization - the "template <>" part is necessary 
    template <> 
    Logger& operator<< (Logger& logger, const wchar_t *wstr) 
    { 
        // convert wstr to an ANSI string and log it 
    } 
    
    template <> 
    Logger& operator<< (Logger& logger, const std::wstring & wstr) 
    { 
        // convert wstr to an ANSI string and log it 
    } 
    
    2

    gerek yoktur dostluğu beyanı:

    class Logger 
    { 
    public: 
        Logger(); 
        ~Logger(); 
    
    template <typename T> 
    inline Logger& Display(T thing) 
    { 
        *out_stream << thing; 
        return *this; 
    } 
    private: 
        std::ostream* out_stream; 
    }; 
    
    template <typename T> 
    Logger& operator<< (Logger& logger, T thing) 
    { 
        return logger.Display(thing); 
    } 
    
    İlgili konular