STL: Probleme mit inserter



  • Hi,

    ich habe versucht bei Google oder hier ne Lösung zu finden, aber ich bekomme es einfach nicht hin. Ich möchte folgendes implementieren (ich weiß, so funktioniert es nicht):

    class A
    {
    public:
        template<typename T> FindChildrenByType(std::insert_iterator<T*> i)
        {
            std::vector<B>::iterator it = m_children.begin();
            while(it != m_children.end())
            {
                T* t = dynamic_cast<T*>(*it);
                if(t != NULL)
                {
                    *i++ = t;
                }
            }
        };
    private:
        std::vector<B*> m_children;
    };
    
    //------------------------------------
    
    class C : public B
    {
    };
    
    //------------------------------------
    
    void SomeMethod()
    {
       std::vector<C*> v;
       myA.FindChildrenByType<C>(std::back_inserter<std::vector<C*> >(v));
    }
    

    So in der Richtung. Ich will in FindChildrenByType() halt nicht den Container vorschreiben.

    Könnt mir da jemand auf die Sprünge helfen? Wäre wirklich super. Alle Beispiele, die ich gefunden habe, benutzen nur STL algorithm methoden wie copy oder so...

    Tausend Dank,
    Data2



  • data2 schrieb:

    Hi,

    ich habe versucht bei Google oder hier ne Lösung zu finden, aber ich bekomme es einfach nicht hin. Ich möchte folgendes implementieren (ich weiß, so funktioniert es nicht):

    Fehlermeldung?

    class A
    {
    public:
        template<typename T> FindChildrenByType(std::insert_iterator<T*> i)
        {
            std::vector<B>::iterator it = m_children.begin(); //FEHLER! std::vector<B*>::iterator müsste passen
            while(it != m_children.end())
            {
      /* ... */
    

    Demnächst auch bitte dazuschreiben was du erreichen willst, nicht einfach Code hinrotzen.



  • #include <vector>
    #include <iterator>
    
    class B
    {
    public:
      virtual ~B()
      {
      }
    };
    
    class C: public B
    {
    };
    
    class A
    {
    public:
      A()
      {
        m_children.push_back(new B);
        m_children.push_back(new B);
        m_children.push_back(new C);
        m_children.push_back(new B);
        m_children.push_back(new B);
        m_children.push_back(new C);
      }
    
      template<typename T, template <typename> class It>
      void FindChildrenByType(It<std::vector<T*> > i)
      {
        std::vector<B*>::iterator it = m_children.begin();
    
        while(it != m_children.end())
        {
          B* b = *it;
          T* t = dynamic_cast<T*>(b);
    
          if(t != NULL)
          {
            *i++ = t;
          }
          ++it;
        }
      };
    
    private:
        std::vector<B*> m_children;
    };
    
    int main(int argc, char* argv[])
    {
      std::vector<C*> v;
    
      A a;
      a.FindChildrenByType<C>(std::back_inserter<std::vector<C*> >(v));
    
      std::cout << v.size() << std::endl;
      return 0;
    }
    

    Sicherlich nicht 100% das, was du willst, wegen vector hardcoded

    void FindChildrenByType(It<std::vector<T*> > i)
    

    ,
    aber ein bissl Spass willst du ja auch noch haben oder?
    Btw. schlechtes Minimalbeispiel mit x Fehlern.



  • @pumuckl Dachte, ich hätt' das erwähnt. Ich will von einer Klasse (class A), die eine Menge von Kindern von Typ B* hat, nur diejendigen Elemente erfragen, die von einem bestimmten Typ ableiten der von B ableitet (im Beispiel class C). Um nicht von irgendeinem bestimmten STL Container abzuhängen, wollte ich das über irgendeinem inserter oder insert_iterator oder was auch immer (dafür habe ich ja gepostet) lösen.

    @der_library_builder Hmm, bei deiner Lösung könnt ich auch einfach ne Referenz auf nen std::vector<T*> übergeben und mit push_back die Treffer einfügen. Das mit den Fehlern tut mir Leid. Sollte auch eigentlich kein vollständiges Minimalbeispiel sein, sondern nur das skizzieren, was ich implementieren will. Hab's nur im Browser "gecoded". Kann also schon rein, dass der ein oder andere Tippfehler drin ist...

    Nun ja, gibt's denn ne Lösung, ohne von einem bestimmten Container abzuhängen? Bei std::copy geht's ja auch. Oder ist dort für jeden Container ne Überladung vorhanden? Leider kann ich die VC++ Implementierung von std::copy nicht nachvollziehen.



  • Warum schreibst Du

    template<typename T> FindChildrenByType(std::insert_iterator<T*> i)
    

    statt

    template<typename T, typename OutputIterator>  
        void FindChildrenByType(OutputIterator i)
    

    ?

    Erstens passt der Parameter T* nicht zum Template insert_iterator weil's nicht der Container ist und zweitens benutzt Du unten auch einen back_insert_iterator.

    Was Du wahrscheinlich damit ausdrücken wolltest war folgendes (C++0x):

    template<typename T, typename OutIter>  
          requires oi = OutputIterator<OutIter>
                && Convertible<T*,oi::value_type>  
        void FindChildrenByType(OutputIterator i)
    

    In C++03 könntest Du das per SFINAE und type traits erreichen.

    In SomeMethod brauchst Du den Template-Parameter für std::back_inserter auch nicht mit angeben. Dafür gibt's ja "template argument deduction".

    void SomeMethod()
    {
       std::vector<C*> v;
       myA.FindChildrenByType<C>(std::back_inserter(v));
    }
    

    Gruß,
    SP



  • Hmm, bei deiner Lösung könnt ich auch einfach ne Referenz auf nen std::vector<T*> übergeben und mit push_back die Treffer einfügen.

    Das sollte einen Weg veranschaulichen, ein wenig Eigeninitiative kann man schon erwarten oder? 😃
    Aber bitte...:

    #include <vector>
    #include <deque>
    #include <iterator>
    
    class B
    {
    public:
      virtual ~B()
      {
      }
    };
    
    class C: public B
    {
    };
    
    class A
    {
    public:
      A()
      {
        m_children.push_back(new B);
        m_children.push_back(new B);
        m_children.push_back(new C);
        m_children.push_back(new B);
        m_children.push_back(new B);
        m_children.push_back(new C);
      }
    
      template<typename T, template <typename T*> class Container, template <typename> class It>
      void FindChildrenByType(It<Container> i)
      {
        std::vector<B*>::iterator it = m_children.begin();
    
        while(it != m_children.end())
        {
          B* b = *it;
          T* t = dynamic_cast<T*>(b);
    
          if(t != NULL)
          {
            *i++ = t;
          }
          ++it;
        }
      };
    
    private:
        std::vector<B*> m_children;
    };
    
    int main(int argc, char* argv[])
    {
      std::vector<C*> v;
      std::deque<C*> d;
    
      A a;
      a.FindChildrenByType<C>(std::back_inserter<std::vector<C*> >(v));
      a.FindChildrenByType<C>(std::back_inserter<std::deque<C*> >(d));
    
      std::cout << v.size() << std::endl;
      std::cout << d.size() << std::endl;
      std::cin.get();
      return 0;
    }
    


  • der_library_builder schrieb:

    Hmm, bei deiner Lösung könnt ich auch einfach ne Referenz auf nen std::vector<T*> übergeben und mit push_back die Treffer einfügen.

    Das sollte einen Weg veranschaulichen, ein wenig Eigeninitiative kann man schon erwarten oder? 😃
    Aber bitte...:

    Ja, könnt ich dir Recht geben, dass man Eigeninitiative erwarten kann. Ich mag es auch nicht, wenn Leute fragen, wie man einen int in einen long casten kann, ohne nachzudenken. Allerdings habe ich Konstrukte wie "template <typename T*> class Container" noch nie gesehen (kannte bisher nur <typename X, typename Y, ...>), und kappiere sie ganz abgesehen davon auch nicht wirklich. Insofern ist es ja nicht sehr verwunderlich, dass ich nicht in der Lage bin, per Eigeninitiative auf ne Lösung zu kommen, und hoffentlich nachvollziehbar, dass ich nochmal nachfrage.

    Freut mich aber, da die Implementierung genau das macht, was ich wollte. Danke 🙂


Anmelden zum Antworten