9
votes

Comment suis-je fortement typé de types non primitifs?

Observez le programme suivant dans lequel une fonction accepte à la fois le type attendu et tout type qui est un type TYPEDEF de ce type.

//I want the functionality, but these are NOT the same type!
class Gadget: public Widget{
    operator Widget() = delete;
};


10 commentaires

Je suppose que je vais class widgetbase , et do widget de classe: widget publicbase ; Gadget de classe: Widget publicbase .


@zneak: C'est ce que boost_strong_typedf fait.


@DEduplicator en regardant la mise en œuvre STORT_TYPEDEF utilise un membre et non sur l'héritage.


Ce n'est pas que Strong_typedf ne fonctionne que pour des types primitifs, mais il faut que le type d'argument soit totalement commandé ( opérateur == , opérateur << / code>) Vous pouvez peut-être leur fournir ou simplement utiliser le code de forte_typedf moins la commande.


@PMR: Voyez-vous toujours un message Zneaks? Je ne.


@PMR "Pourquoi cela nécessite-t-il de commander?" Je me demande.


Vous voulez un type gadget qui est comme widget mais pas comme widget . Cela aiderait-il à prendre un pas en arrière et à réfléchir à ce que vous essayez de déclarer?


@Trevor: Probablement au plus profond de la sérialisation de Boost. Néanmoins, n'a pas trouvé d'endroit mais les sources où elle est documentée.


Je suppose que vous voulez avoir fonctions mutuellement exclusives pour les deux types? Parce que si la barrière ne doit fonctionner que dans une voie, vous pouvez simplement inverser la relation héritabilité (vous pouvez toujours trancher, mais non implicitement jeté).


Pour des fonctions mutuellement exclusives, vous pouvez rendre le widget et le gadget hériter d'une base commune.


3 Réponses :


1
votes

Peut-être que vous pourriez utiliser l'héritage privé et certains en utilisant code> S?

class Gadget : Widget { using Widget::Widget; using Widget::foo; ... };


1 commentaires

Je pense que c'est une solution correcte en supposant qu'il n'y ait pas trop de méthodes ou de membres de données pour énumérer.



6
votes

En gros, vous avez besoin de deux classes non liées avec le même comportement. J'utiliserais un modèle paramétré pour cela:

template<int tag> class WidgetGadget { ... };
typedef WidgetGadget<0> Widget;
typedef WidgetGadget<1> Gadget;


0 commentaires

3
votes

boost_strong_typedf suppose en fait que les types sont équatables ( == code>), assignable ( = code>) et moins que comparable ( ).

Si votre type n'est pas, la macro donne le code de code qui ne compile pas, comme vous avez été témoin. Vous pouvez faire rouler votre propre macro ou fournir des implémentations pour les opérations requises. P>

Vous pouvez trouver un personnalisé_strong_typef code> dans cette réponse de Februari 2012: Comment utiliser des opérateurs de comparaison sur la variante avec des types contenus? strong>, qui évite explicitement l'obtention du comportement de comparaison par défaut P>

Mise à jour forte> a rendu l'exemple plus explicite pour votre cas d'utilisation, le voir Vivez sur Coliru strong> p>

//a user defined type
class Widget{};
class Frobnicator{};

/////////////////////////////////////////////////////
// copied and reduced from boost/strong_typedef.hpp
#define CUSTOM_STRONG_TYPEDEF(T, D)                                 \
struct D                                                            \
    /*: boost::totally_ordered1< D           */                     \
    /*, boost::totally_ordered2< D, T        */                     \
    /*> >                                    */                     \
{                                                                   \
    T t;                                                            \
    explicit D(const T t_) : t(t_) {};                              \
    D(){};                                                          \
    D(const D & t_) : t(t_.t){}                                     \
    D & operator=(const D & rhs) { t = rhs.t; return *this;}        \
    D & operator=(const T & rhs) { t = rhs; return *this;}          \
    explicit operator const T & () const {return t; }               \
    explicit operator T & () { return t; }                          \
    /*bool operator==(const D & rhs) const { return t == rhs.t; } */\
    /*bool operator<(const D & rhs) const { return t < rhs.t; }   */\
};

CUSTOM_STRONG_TYPEDEF(Widget, Gadget)
CUSTOM_STRONG_TYPEDEF(Frobnicator, Normalcy)

void acceptWidget(Widget){}
void acceptGadget(Gadget){}
void acceptFrobnicator(Frobnicator){}
void acceptNormalcy(Normalcy){}

int main(){

    //make the two "different types" (well.. they're not really different as you will see)
    Widget w;
    Gadget g;

    //call a function that should ONLY accept Widgets
    acceptWidget(w); //works (good)
    acceptGadget(g);

    //acceptWidget(g); // Error
    //acceptGadget(w); // Error
    // but we can enjoy conversions if we summon them
    acceptWidget(static_cast<Widget&>(g));

    Frobnicator f;
    Normalcy n;
    acceptFrobnicator(f);
    acceptNormalcy(n);

}


4 commentaires

Travailler pour le problème donné dans la question initiale, il faudrait commenter les deux dernières méthodes pour l'opérateur T. Il s'agit d'une solution OK, mais il faudrait être réécrit à nouveau et à nouveau pour traiter différents types, et donc Les macros devraient être nommées de manière unique.


Je ne vois pas ce que tu veux dire. Je viens de citer principalement l'autre réponse. Mais, en faisant les conversions explicites fera-t-il, et non, vous n'avez pas à écrire cela sur et plus? Mise à jour ma réponse. Voyez-le Vivez sur Coliru **


Ah! Je vois à propos de l'explicite maintenant. J'ai ajouté votre exemple de programme pour illustrer la manière dont cette macro ne peut être utilisée que pour un type de fonctionnalité de classe. Ainsi, je devrais écrire plusieurs macros pour gérer ces différents cas. Coliru.stacked-crooked.com/a/8D80373EBD596C61


@Trevorhickey oh. Bien. Je reçois cela maintenant, mais cela n'a jamais été une partie de votre question: s. Leçon: Avoir les conditions requises est essentielle pour obtenir la bonne solution . Notez également que je do répondez également à la première partie (1.) de votre question, contrairement à l'une des autres réponses. Je pense que vous voudrez utiliser la réponse de Grep, mais ce n'est pas ce que vous avez posé sur: /