polymorphism on template parameters

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Renato Golin

    polymorphism on template parameters


    Hi all,

    I'm fiddling with policies but I'm having some problems...

    My Code:

    class MovePolicy { };
    class EatPolicy { };
    class ReproducePolicy { };

    template <
    class Move = MovePolicy,
    class Eat = EatPolicy,
    class Reproduce = ReproducePolicy
    >
    class Thing : public Move, Eat, Reproduce
    {
    public:
    Thing() { }
    virtual ~Thing() { }
    };

    class NoMove : public MovePolicy { };
    class NoEat : public EatPolicy { };
    class NoReproduce : public ReproducePolicy { };

    class Stone : public Thing <NoMove, NoEat, NoReproduce>
    {
    public:
    Stone() { }
    ~Stone() { }
    };

    int
    main () {
    Thing<>* s = new Stone();
    return 0;
    }

    I get the error:

    In function ‘int main()’:
    error: cannot convert ‘Stone*’ to ‘Thing<MovePo licy, EatPolicy,
    ReproducePolicy >*’ in initialization


    Any pointers (that doesn't start with 0x...) on the subject are appreciated.

    cheers,
    --renato

    --
    Reclaim your digital rights, eliminate DRM, learn more at

  • Renato Golin

    #2
    Re: polymorphism on template parameters


    Addendum: This works, of course... but won't give me the freedom I need
    to do what I want.


    class MovePolicy { };
    class EatPolicy { };
    class ReproducePolicy { };

    class NoMove : public MovePolicy { };
    class NoEat : public EatPolicy { };
    class NoReproduce : public ReproducePolicy { };

    template <
    class Move = NoMove,
    class Eat = NoEat,
    class Reproduce = NoReproduce
    >
    class Thing : public Move, Eat, Reproduce
    {
    public:
    Thing() { }
    virtual ~Thing() { }
    };

    class Stone : public Thing <NoMove, NoEat, NoReproduce>
    {
    public:
    Stone() { }
    ~Stone() { }
    };

    int
    main () {
    Thing<>* s = new Stone();
    return 0;
    }


    cheers,
    --renato


    --
    Reclaim your digital rights, eliminate DRM, learn more at

    Comment

    • Joe Greer

      #3
      Re: polymorphism on template parameters

      Renato Golin <rengolin@gmail .comwrote in
      news:48984b94$0 $639$da29aeef@n ewsread.sanger. ac.uk:
      >
      Hi all,
      >
      I'm fiddling with policies but I'm having some problems...
      >
      I get the error:
      >
      In function ‘int main()’:
      error: cannot convert ‘Stone*’ to ‘Thing<MovePo licy, EatPolicy,
      ReproducePolicy >*’ in initialization
      >
      >
      Any pointers (that doesn't start with 0x...) on the subject are
      appreciated.
      >
      cheers,
      --renato
      >
      Sadly, that is both the curse and blessing of policy based design.
      Different template parameters create completely new types. The template
      name itself doesn't imply interaction capability between the instances.
      That is one of the reasons that shared_ptr<in TR1 isn't a policy based
      smart pointer.

      I have two suggestions as to how to organize things to get around this
      feature of templates.

      First, Instead of policies, you can use strategies that get
      configured/set by the constructor. In other words, don't use templates
      in this way if you want the resulting types to interact as if they were
      the same type.

      Or, you can define an interface for the basic 'Thing'-ness and make all
      your templated classes inherit from that and only use the template for
      construction. i.e.

      class IThing
      {
      public:
      virtual void DoThing() = 0;
      virtual ~IThing() {}
      };

      class MovePolicy { };
      class EatPolicy { };
      class ReproducePolicy { };

      template <
      class Move = MovePolicy,
      class Eat = EatPolicy,
      class Reproduce = ReproducePolicy
      >
      class Thing : public IThing, Move, Eat, Reproduce
      {
      public:
      Thing() { }
      virtual ~Thing() { }
      virtual DoThing() {}
      };

      class NoMove : public MovePolicy { };
      class NoEat : public EatPolicy { };
      class NoReproduce : public ReproducePolicy { };

      class Stone : public Thing <NoMove, NoEat, NoReproduce>
      {
      public:
      Stone() { }
      ~Stone() { }
      };

      int
      main () {
      IThing * s = static_cast<ITh ing *>(new Stone());
      s ->DoThing();
      delete s; // virtual destructor lets this work
      return 0;
      }

      HTH,
      joe

      Comment

      • Pete Becker

        #4
        Re: polymorphism on template parameters

        On 2008-08-05 08:46:12 -0400, Renato Golin <rengolin@gmail .comsaid:
        >
        class Stone : public Thing <NoMove, NoEat, NoReproduce>
        {
        public:
        Stone() { }
        ~Stone() { }
        };
        >
        int
        main () {
        Thing<>* s = new Stone();
        return 0;
        }
        First, when things start getting tangled, reduce the number of template
        arguments. That makes it easier to see what's going on. After you've
        figured things out, add the rest of the details back in.
        >
        I get the error:
        >
        In function ‘int main()’:
        error: cannot convert ‘Stone*’ to ‘Thing<MovePo licy, EatPolicy,
        ReproducePolicy >*’ in initialization
        >
        Thing<MovePolic y etc.and Thing<NoMove etc.are two unrelated types.
        The same problem occurs in this code:

        class Base1 { };
        class Base2 { };
        class Derived : public Base1 { };
        Base2 *ptr = new Derived; // error: no conversion from Derived* to Base2*

        --
        Pete
        Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
        Standard C++ Library Extensions: a Tutorial and Reference
        (www.petebecker.com/tr1book)

        Comment

        • Renato Golin

          #5
          Re: polymorphism on template parameters

          Pete Becker wrote:
          First, when things start getting tangled, reduce the number of template
          arguments. That makes it easier to see what's going on. After you've
          figured things out, add the rest of the details back in.
          Hi Pete,

          The example was too simple to get tangled by that... ;)

          Thing<MovePolic y etc.and Thing<NoMove etc.are two unrelated types.
          The same problem occurs in this code:
          >
          class Base1 { };
          class Base2 { };
          class Derived : public Base1 { };
          Base2 *ptr = new Derived; // error: no conversion from Derived* to
          Base2*
          You don't need to go that far, int* foo = new float; won't work either.

          Templates are defined compile-time and types are created, this is why it
          wouldn't work anyway. What I wanted was another way to have the same
          "effect" as I would have if that did work... ;)

          thanks,
          --renato


          --
          Reclaim your digital rights, eliminate DRM, learn more at

          Comment

          • Renato Golin

            #6
            Re: polymorphism on template parameters

            Joe Greer wrote:
            First, Instead of policies, you can use strategies that get
            configured/set by the constructor. In other words, don't use templates
            in this way if you want the resulting types to interact as if they were
            the same type.
            Hi Joe,

            That's what I wanted to hear, actually. I couldn't see a way of doing it
            with templates and policies, but I could be wrong... :(

            The whole point of my exercise was to explore the potential of policies
            so I don't need to go any further. Using strategies would work for sure,
            but that wouldn't be innovative... ;)

            Or, you can define an interface for the basic 'Thing'-ness and make all
            your templated classes inherit from that and only use the template for
            construction. i.e.
            >
            class IThing
            {
            public:
            virtual void DoThing() = 0;
            virtual ~IThing() {}
            };
            Hum... That might work as I want it... yes.

            There is only one problem, the base class would end up defining all
            methods of all sub-classes. When one adds a new sub-class you need to
            change the base class.

            cheers,
            --renato


            --
            Reclaim your digital rights, eliminate DRM, learn more at

            Comment

            • kwikius

              #7
              Re: polymorphism on template parameters


              "Joe Greer" <jgreer@doublet ake.comwrote in message
              news:Xns9AF161C 82B08Bjgreerdou bletakecom@85.2 14.90.236...
              First, Instead of policies, you can use strategies that get
              configured/set by the constructor. In other words, don't use templates
              in this way if you want the resulting types to interact as if they were
              the same type.
              Yep. Designs that use policies are always rubbish.

              regards
              Andy Little


              Comment

              • anon

                #8
                Re: polymorphism on template parameters

                Joe Greer wrote:
                class IThing
                {
                public:
                virtual void DoThing() = 0;
                virtual ~IThing() {}
                };
                >
                class MovePolicy { };
                class EatPolicy { };
                class ReproducePolicy { };
                >
                template <
                class Move = MovePolicy,
                class Eat = EatPolicy,
                class Reproduce = ReproducePolicy
                class Thing : public IThing, Move, Eat, Reproduce
                {
                public:
                Thing() { }
                virtual ~Thing() { }
                virtual DoThing() {}
                };
                >
                class NoMove : public MovePolicy { };
                class NoEat : public EatPolicy { };
                class NoReproduce : public ReproducePolicy { };
                >
                class Stone : public Thing <NoMove, NoEat, NoReproduce>
                {
                public:
                Stone() { }
                ~Stone() { }
                };
                >
                int
                main () {
                IThing * s = static_cast<ITh ing *>(new Stone());
                Shouldn't this be dynamic_cast< IThing* instead?
                s ->DoThing();
                delete s; // virtual destructor lets this work
                return 0;
                }

                Comment

                • Joe Greer

                  #9
                  Re: polymorphism on template parameters

                  anon <anon@no.nowrot e in news:g79oe1$l7v $1@news01.versa tel.de:
                  >
                  Shouldn't this be dynamic_cast< IThing* instead?
                  >
                  > s ->DoThing();
                  > delete s; // virtual destructor lets this work
                  > return 0;
                  >}
                  >
                  Can be, but doesn't have to be. static_cast<wor ks great if you are
                  dealing with the actual type of the object. You would need dynamic_cast<>
                  if we had a IThing * and wanted to get back to a Stone object though.

                  joe

                  Comment

                  • Joe Greer

                    #10
                    Re: polymorphism on template parameters

                    anon <anon@no.nowrot e in news:g79oe1$l7v $1@news01.versa tel.de:
                    >
                    Shouldn't this be dynamic_cast< IThing* instead?
                    >
                    > s ->DoThing();
                    > delete s; // virtual destructor lets this work
                    > return 0;
                    >}
                    >
                    Can be, but doesn't have to be. static_cast<wor ks great if you are
                    dealing with the actual type of the object. You would need dynamic_cast<>
                    if we had a IThing * and wanted to get back to a Stone object though.

                    joe

                    Comment

                    • Kevin Frey

                      #11
                      Re: polymorphism on template parameters

                      There is only one problem, the base class would end up defining all
                      methods of all sub-classes. When one adds a new sub-class you need to
                      change the base class.
                      That is not the fault of policy-based design, that is an issue intrinsic to
                      polymorphic design.

                      A polymorphic object exposes a set of behaviours that every derived class
                      has to implement in some way or other (even if that implementation is "do
                      nothing").

                      Your implementation only exposed a template class, and no common base class,
                      hence why an IThing interface or similar is needed.

                      Policy-based design only becomes useful when you are trying to
                      *mix-and-match* multiple sets of behaviours into a super-object, so your
                      consideration to use policy-based design was valid in this regard.

                      In your case you have policies on Move, Eat, and Reproduce. Having 3 Move, 3
                      Eat, and 3 Reproduce policies gives you 27 different combinations from 9
                      classes, so as the number of policies/combinations grow, the pay-back is
                      quite large in terms of simplified development.

                      If you tried to do this conventionally you would have to enumerate every
                      possible combination of policies as a separate class.

                      The strategy based approach is just as valid, with the following
                      differences:

                      1. Strategy approach is probably more memory-efficient because the compiler
                      is not generating code for each class/template variation.
                      2. Each strategy (Move, Eat, Reproduce) now has to behave polymorphically so
                      they must be derived from an interface/base class so the main "Thing" class
                      can deal with the strategies polymorphically .
                      3. Strategy approach may be less performant because each call to the
                      strategy is now via a virtual function call.

                      And compile-time optimisation & performance is one of the touted benefits of
                      policy-based development because the compiler "sees the full picture" of the
                      aggregated class, and can optimise accordingly (eg. not call empty inline
                      functions, for example). In your case I would say this is irrelevant.


                      Comment

                      Working...