Question

Je suis un développeur C ++ débutant et j'ai une question sur l'intégration de toString et opérateur ostream via des modèles. J'ai ce 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;
}

Le code a été compilled sans erreur, et l'application exécutée avec succès. Est-il bon d'utiliser une telle approche? Je voulais la mettre en œuvre sans aucune aide de boost.

Était-ce utile?

La solution

L'approche de la mise en œuvre operator<< par lui-même est normal. Mais en utilisant des pièces de la langue que vous ne comprenez pas est une mauvaise pratique (je ne crois pas qu'un débutant peut écrire un tel code). Vous avez deux possibilités: mettre en œuvre une fonction de membre de toString ou operator<<(std::ostream&, T) de surcharge. Cette dernière approche vous permet d'utiliser boost::lexical_cast pour convertir un objet à une chaîne. Quant à moi, cette dernière approche est plus C ++ ish, si vous pouvez faire quelque chose sans fonction de membre, il est préférable de le faire.

Autres conseils

Je pris approche par l'opérateur de flux surcharge solution @Begemoth <<, puis en ajoutant une méthode de commodité « mixin » classe « toString » dans les cas où vous voulez une chaîne immédiate, par exemple pour le débogage:

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

Vous pouvez alors hériter de cette classe dans les cas que vous avez opérateur ostream et il vous donnera une méthode toString sur cette classe. Si vous utilisez boost vous pouvez remplacer la mise en œuvre de l'aide ConvertToString lexical_cast:

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

Si votre classe est conçue pour l'héritage et l'accès polymorphes par des pointeurs alors solution ci-dessus ne fonctionnera pas en tant que modèles sont liés au moment de la compilation, donc une approche différente est nécessaire. La classe mixin suivante peut être utilisée à la place de « ToString » ci-dessus où une méthode virtuelle est définie. Une macro pratique est alors fournie pour implémenter la fonction virtuelle en termes de la fonction de modèle « ConvertToString ». Il faut ajouter dans le corps de la classe de chaque classe dérivée comme il doit être ignoré et le pointeur « ce » lié statiquement au type actuel.

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

#define IMPLEMENT_ToStringVirtual public: std::string toString() const override { return convertToString(*this); }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top