operator == nicht gefunden



  • Hallo,
    was muss ich tun, damit bei folgendem Code der operator == gefunden wird? Warum wird er nicht gefunden?

    #include <iostream>
    
    template<typename T>
    class BinaryTree
    {
    public:
      class ConstIterator
      {
      public:
        ConstIterator(BinaryTree const& tree);
    
      private:
        template<typename>
        friend bool operator == (ConstIterator const&, ConstIterator const&);
    
        BinaryTree const* tree_;
      };
    
      ConstIterator Iterator() const;
    };
    
    template<typename T>
    BinaryTree<T>::ConstIterator::ConstIterator(BinaryTree const& tree)
      : tree_(&tree)
    {
    }
    
    template<typename T>
    typename BinaryTree<T>::ConstIterator BinaryTree<T>::Iterator() const
    {
      return ConstIterator(*this);
    }
    
    template<typename T>
    bool operator == (typename BinaryTree<T>::ConstIterator const& lhs, typename BinaryTree<T>::ConstIterator const& rhs)
    {
      return lhs.tree_ == rhs.tree_;
    }
    
    int main()
    {
      typedef BinaryTree<int> Tree;
    
      Tree tree;
      std::cout << (tree.Iterator() == tree.Iterator()) << std::endl;
    
      return 0;
    }
    

    Meldung:

    gcc-4.5.4 schrieb:

    test.cpp: In function ‘int main()’:
    test.cpp:46:50: error: no match for ‘operator==’ in ‘tree.BinaryTree<T>::Iterator [with T = int]() == tree.BinaryTree<T>::Iterator [with T = int]()’

    Danke!

    MfG
    unwissender


  • Mod

    template<typename T>
    class BinaryTree
    {
    ...
      class ConstIterator
      {
    ...
        template<typename>
        friend bool operator == (ConstIterator const&, ConstIterator const&); // der Templateparameter ist überflüssig und ein Problem: er kann nicht deduziert werden
    ...
    template<typename T> // Templateparameter kann nicht deduziert werden 
    bool operator == (typename BinaryTree<T>::ConstIterator const& lhs, typename BinaryTree<T>::ConstIterator const& rhs);
    

    Die einfachste Lösung besteht in eine inline-friend-Definition einer normalen Funktion

    template<typename T>
    class BinaryTree
    {
    ...
      class ConstIterator
      {
    ...
        friend bool operator == (ConstIterator const&, ConstIterator const&)
        {
         ...
        }
    

    Andere Möglichkeiten (die einen deduzierbaren Templateparameter zur Folge haben) wären:
    - den Vergleichsoperator T allgemeiner fassen und per Predikat und SFINAE auf ConstIterator einzuschränken
    - ConstIterator nicht als Member von BinaryTree zu definieren



  • Danke für deine Antwort.

    camper schrieb:

    Andere Möglichkeiten (die einen deduzierbaren Templateparameter zur Folge haben) wären:
    - den Vergleichsoperator T allgemeiner fassen und per Predikat und SFINAE auf ConstIterator einzuschränken

    Kannst du ein kleines Beispiel dazu geben? Also T allgemeiner fassen ist klar, aber wie genau stellst du dir das mit dem Predikat vor?

    Danke!


  • Mod

    unwissender_ schrieb:

    Danke für deine Antwort.

    camper schrieb:

    Andere Möglichkeiten (die einen deduzierbaren Templateparameter zur Folge haben) wären:
    - den Vergleichsoperator T allgemeiner fassen und per Predikat und SFINAE auf ConstIterator einzuschränken

    Kannst du ein kleines Beispiel dazu geben? Also T allgemeiner fassen ist klar, aber wie genau stellst du dir das mit dem Predikat vor?

    Danke!

    z.B.

    #include <type_traits>
    #include <utility>
    
    template<typename T>
    class BinaryTree
    {
    public:
      class ConstIterator
      {
      public:
        typedef T value_type;
        ConstIterator(BinaryTree const& tree);
    
      private:
        template<typename U>
        friend typename std::enable_if<std::is_same<U, typename Binary_Tree<typename U::value_type>::ConstIterator>::value, bool>::type operator == (const U& lhs, const U& rhs);
    
        BinaryTree const* tree_;
      };
    
      ConstIterator Iterator() const;
    };
    
    template<typename U>
    typename std::enable_if<std::is_same<U, typename Binary_Tree<typename U::value_type>::ConstIterator>::value, bool>::type operator == (const U& lhs, const U& rhs)
    {
      return lhs.tree_ == rhs.tree_;
    }
    

  • Mod

    Eine andere Möglichkeit ist die Verallgemeinerung der Parameter verbunden mit einer eingeschränkten Sichtbarkeit (per ADL), z.B.

    namespace secret
    {
        struct secret_base {};
    
        template <typename T>
        bool operator==(const T& lhs, const T& rhs)
        {
            return lhs.tree_ == rhs.tree_;
        }
    }
    
    template<typename T>
    class BinaryTree
    {
    public:
      class ConstIterator : secret::secret_base // secret ist damit assozierter Namensraum
      {
      public:
        ConstIterator(BinaryTree const& tree);
    
      private:
        friend bool secret::operator==<>(const ConstIterator& lhs, const ConstIterator& rhs);
    
        BinaryTree const* tree_;
      };
    
      ConstIterator Iterator() const;
    };
    


  • Interessant. Danke fuer die Ausfuehrungen! Aber bei der Auswahl belasse ich den operator == einfach als Member-Funktion, sieht zwar ein bisschen komisch aus, ist aber imo noch besser als die Alternativen 🙂


Anmelden zum Antworten