2011-04-29 47 views
2

我是一名初學C++開發人員,我對通過模板的toStringostream運算符集成有疑問。 我有這樣的代碼:C++ toString成員函數和ostream運算符<<通過模板集成

struct MethodCheckerTypes{ 
     typedef unsigned char TrueType; 
     typedef long FalseType; 
    }; 
    template<typename T>struct HasToString{ 
     template<typename K>static typename MethodCheckerTypes::TrueType test(decltype(&K::toString)); 
     template<typename> static typename MethodCheckerTypes::FalseType test(...); 
     static const bool value = sizeof(test<T>(0)) == sizeof(typename MethodCheckerTypes::TrueType); 
     typedef decltype(test<T>(0)) ValueType; 
    }; 

    template<typename T, typename K> struct IfDef{}; 
    template<> struct IfDef<typename MethodCheckerTypes::TrueType, ostream&>{ 
     typedef ostream& type; 
    }; 

    class WithToString{ 
    public: 
     string toString() const{ 
      return "hello"; 
     } 
    }; 

    template<typename F, typename CharT, typename Traits> typename IfDef<typename HasToString<F>::ValueType, basic_ostream<CharT, Traits>&>::type operator<<(basic_ostream<CharT, Traits>& out, const F &ref){ 
     out<<ref.toString().c_str(); 
     return out; 
    } 
int main(int argc, char **argv){ 
    WithToString hasToString; 
    cout<<hasToString<<endl; 
    return 0; 
} 

的代碼已經compilled沒有錯誤,並且應用程序successfuly執行。 使用這種方法很好嗎?我想在沒有任何幫助的情況下實施它。

+0

你是一個初學者* *,並開始從一開始就與*模板*彈(C最危險的特性++)? – Nawaz 2011-04-29 11:25:22

+7

你似乎是一個非常進步的初學者。 :)很高興。 – iammilind 2011-04-29 11:27:07

+1

謝謝。我想說我是初學者模板開發人員。此代碼片段使用C++ 0x功能(decltype)。 – Malasar 2011-04-29 11:35:09

回答

1

本身實施operator<<的方法是正常的。但使用你不明白的部分語言是不好的做法(我不相信初學者可以寫這樣的代碼)。您有兩種選擇:實施toString成員函數或超載operator<<(std::ostream&, T)。後一種方法使您能夠使用boost::lexical_cast將對象轉換爲字符串。至於我,後一種方法是更多的C++ ish,如果你可以做一些沒有成員函數的東西,最好這樣做。

+0

謝謝!我想BOOSTless方法。關於第一個建議:你的意思是我所有的類都必須使用toString從基本抽象類繼承。我想過這樣的方式,但想要更通用的解決方案。 – Malasar 2011-04-29 11:54:52

+0

@Malasar從這些普通類繼承似乎毫無意義(除非類型系統迫使你這麼做)。 BOOSTless方法boost :: lexical_cast'使用'std :: stringstream'進行轉換(在一般情況下),實現類似的功能並不難。 – Begemoth 2011-04-29 12:01:29

+0

明白了!我會檢查lexical_cast的方式。非常感謝您的迴應! – Malasar 2011-04-29 12:04:26

0

我把方法使用@Begemoth解決重載流運算符< <,再加入方便「混入」類「的toString」在你想立即串案件的方法,例如用於調試:

template<typename T> 
class ToString 
{ 
public: 
    std::string toString() const 
    { 
     return convertToString(static_cast<const T&>(*this)); 
    } 
}; 

template<typename T> 
inline std::string convertToString(const T& value) 
{ 
    std::stringstream s; 
    s << value; 
    return s.str(); 
} 

如果你有ostream運算符,你可以從這個類繼承,它會給你一個toString方法。如果你正在使用升壓那麼你可以使用lexical_cast的替代實施convertToString的:

template<typename T> 
inline std::string convertToString(const T& value) 
{ 
    return boost::lexical_cast<std::string>(value); 
} 

如果你的類是專爲繼承和通過指針多態性訪問,則上述溶液作爲模板在編​​譯時綁將無法正常工作,所以需要一種不同的方法。下面的mixin類可以用來代替定義虛擬方法的上面的「ToString」。然後提供一個方便的宏來實現模板函數「convertToString」的虛函數。這必須被添加到每個派生類的類體中,因爲它需要被覆蓋,並且「this」指針靜態地綁定到當前類型。

class ToStringVirtual 
{ 
public: 
    virtual ~ToStringVirtual() {} 
    virtual std::string toString() const = 0; 
}; 

#define IMPLEMENT_ToStringVirtual public: std::string toString() const override { return convertToString(*this); } 
相關問題