Search code examples
c++templatesc++11ostreamsfinae

C++ toString member-function and ostream operator << integration via templates


I'm a beginner C++ developer and I have a question about toString and ostream operator integration via templates. I have such code:

    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;
}

The code has been compilled without errors, and the application executed successfuly. Is it good to use such an approach? I wanted to implement it without any help from boost.


Solution

  • The approach to implementing operator<< by itself is normal. But using parts of the language you do not understand is bad practice (I do not believe that a beginner can write such code). You have two alternatives: to implement a toString member function or overload operator<<(std::ostream&, T). The latter approach enables you to use boost::lexical_cast to convert an object to a string. As for me, the latter approach is more C++ish, if you can do something without a member function it is better to do so.