How do you implement this Python idiom in C++

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • alainpoint@yahoo.fr

    #1

    How do you implement this Python idiom in C++

    Hello,

    I have the need to write the equivalent of Python class methods in C++.

    Chuck Allison proposes the following
    (http://www.artima.com/cppsource/simple.html):
    #include <iostream>
    using namespace std;

    // A base class that provides counting
    template<class Tclass Counted {
    static int count;
    public:
    Counted() { ++count; }
    Counted(const Counted<T>&) { ++count; }
    ~Counted() { --count; }
    static int getCount() { return count; }

    };

    template<class Tint Counted<T>::cou nt = 0;

    // Curious class definitions
    class CountedClass : public Counted<Counted Class{};
    class CountedClass2 : public Counted<Counted Class2{};

    It apparently works but in fact it doesn't:
    If you derive from such a class, you get the count of the parent class,

    not of the derived class.
    class CountedClass3 : public CountedClass {};

    int main() {
    CountedClass a;
    cout << CountedClass::g etCount() << endl; // 1
    CountedClass b;
    cout << CountedClass::g etCount() << endl; // 2
    CountedClass3 c;
    cout << CountedClass3:: getCount() << endl; // 3 and should be 1
    cout << CountedClass::g etCount() << endl; // 3 and should be 2

    }

    I am no C++ expert but i guess there might be some in the Python and
    C++ newsgroups.

    Alain

  • Jon Clements

    #2
    Re: How do you implement this Python idiom in C++


    alainpoint@yaho o.fr wrote:
    // Curious class definitions
    class CountedClass : public Counted<Counted Class{};
    class CountedClass2 : public Counted<Counted Class2{};
    >
    It apparently works but in fact it doesn't:
    If you derive from such a class, you get the count of the parent class,
    >
    not of the derived class.
    class CountedClass3 : public CountedClass {};
    >
    Hint: where's the template parameter gone as per the previous two
    statements...

    Jon.

    Comment

    • Pierre Barbier de Reuille

      #3
      Re: How do you implement this Python idiom in C++

      alainpoint@yaho o.fr wrote:
      Hello,
      >
      I have the need to write the equivalent of Python class methods in C++.
      >
      Chuck Allison proposes the following
      (http://www.artima.com/cppsource/simple.html):
      #include <iostream>
      using namespace std;
      >
      // A base class that provides counting
      template<class Tclass Counted {
      static int count;
      public:
      Counted() { ++count; }
      Counted(const Counted<T>&) { ++count; }
      ~Counted() { --count; }
      static int getCount() { return count; }
      >
      };
      >
      template<class Tint Counted<T>::cou nt = 0;
      >
      // Curious class definitions
      class CountedClass : public Counted<Counted Class{};
      class CountedClass2 : public Counted<Counted Class2{};
      >
      It apparently works but in fact it doesn't:
      If you derive from such a class, you get the count of the parent class,
      >
      not of the derived class.
      class CountedClass3 : public CountedClass {};
      >
      int main() {
      CountedClass a;
      cout << CountedClass::g etCount() << endl; // 1
      CountedClass b;
      cout << CountedClass::g etCount() << endl; // 2
      CountedClass3 c;
      cout << CountedClass3:: getCount() << endl; // 3 and should be 1
      cout << CountedClass::g etCount() << endl; // 3 and should be 2
      >
      }
      >
      I am no C++ expert but i guess there might be some in the Python and
      C++ newsgroups.
      >
      Alain
      >
      Why don't you post the Python code you want to "translate" ? Here, I
      just don't know what you want to achieve !!

      Pierre

      Comment

      • alainpoint@yahoo.fr

        #4
        Re: How do you implement this Python idiom in C++


        Jon Clements wrote:
        alainpoint@yaho o.fr wrote:
        // Curious class definitions
        class CountedClass : public Counted<Counted Class{};
        class CountedClass2 : public Counted<Counted Class2{};

        It apparently works but in fact it doesn't:
        If you derive from such a class, you get the count of the parent class,

        not of the derived class.
        class CountedClass3 : public CountedClass {};
        >
        Hint: where's the template parameter gone as per the previous two
        statements...
        >
        Jon.
        You miss the point; i want to derive a class and inherit all properties
        without worrying about those implementation details. The Python code is
        much cleaner in that respect. My post is about whether it is possible
        to get such a clean interface in C++

        Alain

        Comment

        • Jon Clements

          #5
          Re: How do you implement this Python idiom in C++


          alainpo...@yaho o.fr wrote:
          You miss the point; i want to derive a class and inherit all properties
          without worrying about those implementation details. The Python code is
          much cleaner in that respect. My post is about whether it is possible
          to get such a clean interface in C++
          I was simply pointing out that your statement declaring that it didn't
          work, wasn't accurate, because the code you'd used was incorrect.

          Jon

          Comment

          • Noah Roberts

            #6
            Re: How do you implement this Python idiom in C++


            alainpoint@yaho o.fr wrote:
            I am no C++ expert but i guess there might be some in the Python and
            C++ newsgroups.
            >
            Provide compilable code that exibits your problem. The technique is
            sound; you must be screwing up somehow.


            #include <iostream>

            using namespace std;

            template <typename T>
            class counted
            {
            static int count;

            public:
            counted() { ++ count; }
            counted(const counted<T&) { ++ count; }
            virtual ~counted() { -- count; }
            static int getCount() { return count; }
            };

            template <typename T>
            int counted<T>::cou nt = 0;

            class C1 : public counted<C1>
            {
            public:
            C1() : counted() {}
            };

            class C2 : public counted<C2>
            {
            public:
            C2() : counted() {}
            };

            int main(void)
            {
            C1 c11;
            C1 c12;
            C2 c2;

            cout << C1::getCount() << endl;
            cout << C2::getCount() << endl;

            int c;
            cin >c;

            return 0;
            }


            output is 2 and 1 as expected. Removing the constructors in the
            derivatives doesn't change that fact.

            Comment

            • Rob Williscroft

              #7
              Re: How do you implement this Python idiom in C++

              wrote in news:1154015441 .807624.35160@i 42g2000cwa.goog legroups.com in
              comp.lang.pytho n:
              #include <iostream>
              using namespace std;
              >
              // A base class that provides counting
              template<class Tclass Counted {
              static int count;
              };
              >
              template<class Tint Counted<T>::cou nt = 0;
              >
              // Curious class definitions
              class CountedClass : public Counted<Counted Class{};
              class CountedClass2 : public Counted<Counted Class2{};
              >
              It apparently works but in fact it doesn't:
              If you derive from such a class, you get the count of the parent class,
              You are mistaken about how it should work in the first place.
              It may well be that it doesn't do what you wan't it to.

              To translate the python idom into C++ you need to replace
              derivation with the CRTP (*) code the author supplied.

              *) CRTP = Curiosly Recuring Template Pattern
              >
              not of the derived class.
              class CountedClass3 : public CountedClass {};
              Don't use the above always use:

              class CountedClass3 : public Counted< CountedClass3 >
              {
              };

              Note that the "classmetho d emulation" stops here, if you need
              it to continue you will need to keep using the CRTP:

              template < typename T = void >
              class CountedClass : public Counted< CountedClass< T
              {
              };

              Create instances:

              CountedClass<cc ; /* T = void */

              Derive (keeping the "classmetho d emulation") using the CRTP:

              template < typename T = void /* So we can "Derive" again */
              class CountedClass2 : public CountedClass< CountedClass2< void
              {
              };

              Note that the trick works by always making the instantition of
              Counted< T you are deriving from unique, CountedClass<ha s
              a base class Counted< CountedClass< void and CountedClass2<>
              has (ultimatly) a base class Counted< CountedClass2< void .

              Ofcouse the next problem is that CRTP-derivation above isn't real
              derivation, this idom translation clearly has a breaking point.

              If this is more than idle curiosity I strongly suggest you post
              a version of the python code you need to translate to C++.

              Rob.
              --

              Comment

              • alainpoint@yahoo.fr

                #8
                Re: How do you implement this Python idiom in C++

                Rob Williscroft wrote:
                If this is more than idle curiosity I strongly suggest you post
                a version of the python code you need to translate to C++.
                For the moment this is just healthy curiosity but i will still post the
                code i would like to see translated:

                class Parent:
                count=0
                def __init__(self):
                self.__class__. count +=1
                @classmethod
                def getcount(cls):
                return cls.count

                class Child(Parent):
                count=0 # replace this line by a 'pass' statement if you don't want
                to reinitialise the count

                a=Parent()
                b=Parent()
                print Parent.getcount () # you get 2
                c=Child()
                d=Child()
                e=Child()
                print Child.getcount( ) # you get 3 (you could get 5 if you don't
                reinitialise the count)

                This is as simple as it can get. I just derive from Parent and i get my
                proper count (added to my parent's if i wish so).
                I wish i could achieve such a code purity in C++.

                Alain

                Comment

                • Noah Roberts

                  #9
                  Re: How do you implement this Python idiom in C++


                  alainpoint@yaho o.fr wrote:
                  Rob Williscroft wrote:
                  >
                  If this is more than idle curiosity I strongly suggest you post
                  a version of the python code you need to translate to C++.
                  >
                  For the moment this is just healthy curiosity but i will still post the
                  code i would like to see translated:
                  >
                  class Parent:
                  count=0
                  def __init__(self):
                  self.__class__. count +=1
                  @classmethod
                  def getcount(cls):
                  return cls.count
                  >
                  class Child(Parent):
                  count=0 # replace this line by a 'pass' statement if you don't want
                  to reinitialise the count
                  >
                  a=Parent()
                  b=Parent()
                  print Parent.getcount () # you get 2
                  c=Child()
                  d=Child()
                  e=Child()
                  print Child.getcount( ) # you get 3 (you could get 5 if you don't
                  reinitialise the count)
                  What happens if you print Parent.getcount () now?

                  Comment

                  • alainpoint@yahoo.fr

                    #10
                    Re: How do you implement this Python idiom in C++


                    Noah Roberts wrote:
                    What happens if you print Parent.getcount () now?
                    You still get 2 since there is no new instance of Parent that was
                    created.

                    Alain

                    Comment

                    • Pierre Barbier de Reuille

                      #11
                      Re: How do you implement this Python idiom in C++

                      alainpoint@yaho o.fr wrote:
                      Rob Williscroft wrote:
                      >
                      >If this is more than idle curiosity I strongly suggest you post
                      >a version of the python code you need to translate to C++.
                      >
                      For the moment this is just healthy curiosity but i will still post the
                      code i would like to see translated:
                      >
                      class Parent:
                      count=0
                      def __init__(self):
                      self.__class__. count +=1
                      @classmethod
                      def getcount(cls):
                      return cls.count
                      >
                      class Child(Parent):
                      count=0 # replace this line by a 'pass' statement if you don't want
                      to reinitialise the count
                      >
                      a=Parent()
                      b=Parent()
                      print Parent.getcount () # you get 2
                      c=Child()
                      d=Child()
                      e=Child()
                      print Child.getcount( ) # you get 3 (you could get 5 if you don't
                      reinitialise the count)
                      >
                      This is as simple as it can get. I just derive from Parent and i get my
                      proper count (added to my parent's if i wish so).
                      I wish i could achieve such a code purity in C++.
                      Well, I hope you understand that this code "purity" is possible only
                      because of the *dynamic* lookup of the variable name ... Thus, the same
                      function, once compiled, will be able to determine, at runtime, where
                      the current variable lies ... At the same time, tries, in Python, to
                      achieve the count of *all* the instances of a class, meaning that you want :

                      a = Parent()
                      b = Child()
                      c = Parent()
                      d = Child()
                      print Child.getcount( ) # 2
                      print Parent.getcount () # 4

                      That time, the automatic name lookup will come in the way as you cannot
                      have two "count" variables accessible from the same class.
                      For C++ the problem is inverse, you have a way to obtain the second
                      thing (using templates or macro), but the first is harder.

                      Pierre

                      PS: here is my solution in C++


                      #include <iostream>
                      using namespace std;

                      template <class T>
                      struct Counted
                      {
                      Counted() { ++count; }
                      Counted( Counted const& ) { ++count; }
                      virtual ~Counted() { --count; }
                      static size_t getCount() { return count; }
                      protected:
                      static size_t count;
                      };

                      template <class T>
                      size_t Counted<T>::cou nt = 0;

                      struct cA : public Counted<cA>
                      {
                      int a;
                      };

                      struct cB : public Counted<cB>, public cA
                      {
                      // Needed to be sure of which getCount is called in cB
                      using Counted<cB>::ge tCount;
                      };

                      int main()
                      {
                      cA a,b,c;
                      cB d,e,f;
                      a.a = 1;
                      b.a = 1;
                      c.a = 1;
                      d.a = 1;
                      e.a = 1;
                      f.a = 1;
                      {
                      cA g;
                      g.a = 1;
                      cout << "#cA = " << cA::getCount() << endl; // 7
                      cout << "#cB = " << cB::getCount() << endl; // 3
                      }
                      cout << "#cA = " << cA::getCount() << endl; // 6
                      cout << "#cB = " << cB::getCount() << endl; // 3
                      return 0;
                      }

                      Comment

                      • alainpoint@yahoo.fr

                        #12
                        Re: How do you implement this Python idiom in C++


                        Pierre Barbier de Reuille wrote:
                        alainpoint@yaho o.fr wrote:
                        Rob Williscroft wrote:
                        If this is more than idle curiosity I strongly suggest you post
                        a version of the python code you need to translate to C++.
                        For the moment this is just healthy curiosity but i will still post the
                        code i would like to see translated:

                        class Parent:
                        count=0
                        def __init__(self):
                        self.__class__. count +=1
                        @classmethod
                        def getcount(cls):
                        return cls.count

                        class Child(Parent):
                        count=0 # replace this line by a 'pass' statement if you don't want
                        to reinitialise the count

                        a=Parent()
                        b=Parent()
                        print Parent.getcount () # you get 2
                        c=Child()
                        d=Child()
                        e=Child()
                        print Child.getcount( ) # you get 3 (you could get 5 if you don't
                        reinitialise the count)

                        This is as simple as it can get. I just derive from Parent and i get my
                        proper count (added to my parent's if i wish so).
                        I wish i could achieve such a code purity in C++.
                        >
                        Well, I hope you understand that this code "purity" is possible only
                        because of the *dynamic* lookup of the variable name ... Thus, the same
                        function, once compiled, will be able to determine, at runtime, where
                        the current variable lies ... At the same time, tries, in Python, to
                        achieve the count of *all* the instances of a class, meaning that you want :
                        >
                        a = Parent()
                        b = Child()
                        c = Parent()
                        d = Child()
                        print Child.getcount( ) # 2
                        print Parent.getcount () # 4
                        >
                        That time, the automatic name lookup will come in the way as you cannot
                        have two "count" variables accessible from the same class.
                        For C++ the problem is inverse, you have a way to obtain the second
                        thing (using templates or macro), but the first is harder.
                        >
                        Pierre
                        >
                        PS: here is my solution in C++
                        >
                        >
                        #include <iostream>
                        using namespace std;
                        >
                        template <class T>
                        struct Counted
                        {
                        Counted() { ++count; }
                        Counted( Counted const& ) { ++count; }
                        virtual ~Counted() { --count; }
                        static size_t getCount() { return count; }
                        protected:
                        static size_t count;
                        };
                        >
                        template <class T>
                        size_t Counted<T>::cou nt = 0;
                        >
                        struct cA : public Counted<cA>
                        {
                        int a;
                        };
                        >
                        struct cB : public Counted<cB>, public cA
                        {
                        // Needed to be sure of which getCount is called in cB
                        using Counted<cB>::ge tCount;
                        };
                        >
                        int main()
                        {
                        cA a,b,c;
                        cB d,e,f;
                        a.a = 1;
                        b.a = 1;
                        c.a = 1;
                        d.a = 1;
                        e.a = 1;
                        f.a = 1;
                        {
                        cA g;
                        g.a = 1;
                        cout << "#cA = " << cA::getCount() << endl; // 7
                        cout << "#cB = " << cB::getCount() << endl; // 3
                        }
                        cout << "#cA = " << cA::getCount() << endl; // 6
                        cout << "#cB = " << cB::getCount() << endl; // 3
                        return 0;
                        }
                        I thank you for your response. The equivalent of your solution is
                        posted hereunder:
                        class cA(object):
                        count=0
                        def __init__(self):
                        self.__class__. count +=1
                        @classmethod
                        def getcount(cls):
                        return cls.count
                        def __del__(self):
                        self.__class__. count -=1
                        class cB(cA):
                        count=0
                        def __init__(self):
                        super(cB,self). __init__()
                        for klass in self.__class__. __bases__:
                        klass.count +=1

                        a=cA() ; b=cA(); c= cA()
                        d=cB() ; e=cB(); f= cB()
                        a.a=1;b.a=1;c.a =1;d.a=1;e.a=1; f.a=1
                        g=cA()
                        g.a=1
                        print '#cA=',cA.getco unt() # 7
                        print '#cB=',cB.getco unt() # 3
                        del g
                        print '#cA=',cA.getco unt() # 6
                        print '#cB=',cB.getco unt() # 3

                        There is nothing impossible in Python ;-)

                        Alain

                        Comment

                        • Pierre Barbier de Reuille

                          #13
                          Re: How do you implement this Python idiom in C++

                          alainpoint@yaho o.fr wrote:
                          Pierre Barbier de Reuille wrote:
                          [...]
                          >
                          I thank you for your response. The equivalent of your solution is
                          posted hereunder:
                          class cA(object):
                          count=0
                          def __init__(self):
                          self.__class__. count +=1
                          @classmethod
                          def getcount(cls):
                          return cls.count
                          def __del__(self):
                          self.__class__. count -=1
                          class cB(cA):
                          count=0
                          def __init__(self):
                          super(cB,self). __init__()
                          for klass in self.__class__. __bases__:
                          klass.count +=1
                          >
                          a=cA() ; b=cA(); c= cA()
                          d=cB() ; e=cB(); f= cB()
                          a.a=1;b.a=1;c.a =1;d.a=1;e.a=1; f.a=1
                          g=cA()
                          g.a=1
                          print '#cA=',cA.getco unt() # 7
                          print '#cB=',cB.getco unt() # 3
                          del g
                          print '#cA=',cA.getco unt() # 6
                          print '#cB=',cB.getco unt() # 3
                          >
                          There is nothing impossible in Python ;-)
                          >
                          Alain
                          >
                          Well, nothing is impossible, but it is now much much more complex ! As a
                          proof of that, your version does not work completely :P (try deleting d
                          for example).

                          I add a working version, but you will also notice that I have to
                          *explicitly* walk over all the classes of the hierarchy, testing for the
                          one who have a "count" attribute, hoping that this attribute is indeed
                          for counting the number of objects and not anything else ... so the
                          solution is quite fragile and very slow.

                          class cA(object):
                          count=0
                          def __init__(self):
                          self.__class__. count +=1
                          for klass in self.__class__. __bases__:
                          if hasattr( klass, "count" ):
                          klass.count += 1

                          @classmethod
                          def getcount(cls):
                          return cls.count
                          def __del__(self):
                          self.__class__. count -=1
                          for klass in self.__class__. __bases__:
                          if hasattr( klass, "count" ):
                          klass.count -= 1
                          class cB(cA):
                          count=0

                          a=cA() ; b=cA(); c= cA()
                          d=cB() ; e=cB(); f= cB()
                          a.a=1;b.a=1;c.a =1;d.a=1;e.a=1; f.a=1
                          g=cA()
                          g.a=1
                          print '#cA=',cA.getco unt() # 7
                          print '#cB=',cB.getco unt() # 3
                          del g
                          del d
                          print '#cA=',cA.getco unt() # 5
                          print '#cB=',cB.getco unt() # 2

                          Pierre

                          Comment

                          • alainpoint@yahoo.fr

                            #14
                            Re: How do you implement this Python idiom in C++


                            Pierre Barbier de Reuille wrote:
                            alainpoint@yaho o.fr wrote:
                            Pierre Barbier de Reuille wrote:
                            [...]

                            I thank you for your response. The equivalent of your solution is
                            posted hereunder:
                            class cA(object):
                            count=0
                            def __init__(self):
                            self.__class__. count +=1
                            @classmethod
                            def getcount(cls):
                            return cls.count
                            def __del__(self):
                            self.__class__. count -=1
                            class cB(cA):
                            count=0
                            def __init__(self):
                            super(cB,self). __init__()
                            for klass in self.__class__. __bases__:
                            klass.count +=1

                            a=cA() ; b=cA(); c= cA()
                            d=cB() ; e=cB(); f= cB()
                            a.a=1;b.a=1;c.a =1;d.a=1;e.a=1; f.a=1
                            g=cA()
                            g.a=1
                            print '#cA=',cA.getco unt() # 7
                            print '#cB=',cB.getco unt() # 3
                            del g
                            print '#cA=',cA.getco unt() # 6
                            print '#cB=',cB.getco unt() # 3

                            There is nothing impossible in Python ;-)

                            Alain
                            >
                            Well, nothing is impossible, but it is now much much more complex ! As a
                            proof of that, your version does not work completely :P (try deleting d
                            for example).
                            >
                            I add a working version, but you will also notice that I have to
                            *explicitly* walk over all the classes of the hierarchy, testing for the
                            one who have a "count" attribute, hoping that this attribute is indeed
                            for counting the number of objects and not anything else ... so the
                            solution is quite fragile and very slow.
                            >
                            class cA(object):
                            count=0
                            def __init__(self):
                            self.__class__. count +=1
                            for klass in self.__class__. __bases__:
                            if hasattr( klass, "count" ):
                            klass.count += 1
                            >
                            @classmethod
                            def getcount(cls):
                            return cls.count
                            def __del__(self):
                            self.__class__. count -=1
                            for klass in self.__class__. __bases__:
                            if hasattr( klass, "count" ):
                            klass.count -= 1
                            class cB(cA):
                            count=0
                            >
                            a=cA() ; b=cA(); c= cA()
                            d=cB() ; e=cB(); f= cB()
                            a.a=1;b.a=1;c.a =1;d.a=1;e.a=1; f.a=1
                            g=cA()
                            g.a=1
                            print '#cA=',cA.getco unt() # 7
                            print '#cB=',cB.getco unt() # 3
                            del g
                            del d
                            print '#cA=',cA.getco unt() # 5
                            print '#cB=',cB.getco unt() # 2
                            >
                            Pierre
                            Good point Pierre. But you'll have to admit that the class usage in
                            Python is much simpler (just derive from the class)
                            class cB(cA):
                            count=0
                            contrarily to the C++ usage where you must remind the compiler of the
                            Counted class in every derived class.

                            In Python, you have to bite only once thru the sour apple ....


                            Alain

                            Comment

                            • benben

                              #15
                              Re: How do you implement this Python idiom in C++

                              You are heading the wrong way...

                              There are a number of ways to implement this but the easiest I can think
                              of is to use RTTI.

                              To get around with counting sub-objects you can rely on virtual
                              inheritance, which only happens at the top of the inheritance tree.

                              Here is a simple demo:

                              #include <iostream>
                              #include <typeinfo>
                              #include <map>

                              class count
                              {
                              public:
                              typedef std::map<const std::type_info* , unsigned intcounts_t;
                              static counts_t counts;

                              const std::type_info* ti;

                              static unsigned int get_count(const std::type_info& c)
                              {return counts[&c];}

                              count(const std::type_info& c):ti(&c){++cou nts[ti];}
                              ~count(){--counts[ti];}
                              };

                              count::counts_t count::counts;

                              class c1: virtual private count
                              {
                              public: c1(): count(typeid(c1 )){}
                              };

                              class c2: public c1, virtual private count
                              {
                              public: c2(): count(typeid(c2 )){}
                              };

                              int main()
                              {
                              c1 t1[3];
                              c2 t2[5];

                              std::cout << count::get_coun t(typeid(c1)) << "\n";
                              << count::get_coun t(typeid(c2)) << "\n";

                              return 0;
                              }

                              Comment

                              Working...