Frage

Ich bin ein C++-Entwickler für Anfänger und habe eine Frage dazu toString Und ostream Betreiberintegration über Templates.Ich habe solchen 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;
}

Der Code wurde fehlerfrei kompiliert und die Anwendung erfolgreich ausgeführt.Ist es sinnvoll, einen solchen Ansatz zu verwenden?Ich wollte es ohne die Hilfe von Boost umsetzen.

War es hilfreich?

Lösung

Der Ansatz zur Implementierung operator<< für sich ist normal. Wenn Sie jedoch Teile der Sprache verwenden, die Sie nicht verstehen, ist eine schlechte Praxis (ich glaube nicht, dass ein Anfänger einen solchen Code schreiben kann). Sie haben zwei Alternativen: um eine implementieren toString Mitgliederfunktion oder Überlastung operator<<(std::ostream&, T). Der letztere Ansatz ermöglicht es Ihnen, zu verwenden boost::lexical_cast Um ein Objekt in eine Zeichenfolge umzuwandeln. Der letztere Ansatz ist mehr C ++ ish. Wenn Sie etwas ohne Mitgliedsfunktion tun können, ist es besser, dies zu tun.

Andere Tipps

Ich habe den Ansatz gewählt, die @Begemoth-Lösung zum Überladen des Stream-Operators << zu verwenden und dann eine praktische „mixin“-Klasse „toString“-Methode hinzuzufügen, in Fällen, in denen Sie eine sofortige Zeichenfolge benötigen, beispielsweise zum Debuggen:

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

Sie können dann von dieser Klasse erben, wenn Sie über den Operator ostream verfügen, und Sie erhalten eine toString-Methode für diese Klasse.Wenn Sie Boost verwenden, können Sie die Implementierung von „convertToString“ durch lexical_cast ersetzen:

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

Wenn Ihre Klasse für Vererbung und polymorphen Zugriff über Zeiger konzipiert ist, funktioniert die obige Lösung nicht, da Vorlagen zur Kompilierzeit gebunden werden. Daher ist ein anderer Ansatz erforderlich.Die folgende Mixin-Klasse kann anstelle von „ToString“ oben verwendet werden, wo eine virtuelle Methode definiert ist.Anschließend wird ein praktisches Makro bereitgestellt, um die virtuelle Funktion im Sinne der Vorlagenfunktion „convertToString“ zu implementieren.Dies muss in den Klassenkörper jeder abgeleiteten Klasse eingefügt werden, da es überschrieben und der „this“-Zeiger statisch an den aktuellen Typ gebunden werden muss.

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

#define IMPLEMENT_ToStringVirtual public: std::string toString() const override { return convertToString(*this); }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top