Very strange problem with namespace

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance

From: Agoston Bejo (gusz1_at_freemail.hu)
Date: 06/12/04

  • Next message: Michael T. Pudelko: "Re: Problems importing DLL"
    Date: Sat, 12 Jun 2004 22:01:52 +0200
    
    

    Hello,
    today is the day of questions for me. :) (That's because I have time mainly
    on the weekends for this.)
    I have tried to create an example code based on the program where the
    problem occured, but as you can see, it got quite lengthy anyway. I'm very
    sorry for that, but this is the shortest I could make that is concentrated
    as tightly as possible around the problem.
    If you take your time and read through the source code, you will notice that
    I marked the critical parts with (*).
    Briefly about the problem: In the code an item_proxy object is used that can
    implicitly be converted to the corresponding value type and used as a
    reference that is returned by an iterator. No matter what, the compiler
    won't found the global operator< that takes value type as parameters when
    you apply it to the item_proxy objects. If the ContainerFront class (that
    contains item_proxy as an inner class) is not defined in namespace N, there
    is no problem. Moreso, operator<< is found without problem in either case.
    I just can't get any sense out of this.

    Thx for your help,
    Gus

    ---------------------------------------------------
    Huge example code (once more, sorry) :
    ---------------------------------------------------

    // xOpLessSucks.cpp : Defines the entry point for the console application.
    //

    #include "stdafx.h"
    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <boost/iterator/iterator_facade.hpp>
    using namespace std;
    using namespace boost;

    // example class that is going to be used as a value type:
    struct C {
     int i;
     C(int i):i(i) {}
     C() {}
    };

    bool operator<(const C& lhs, const C& rhs) { // (*)
     return lhs.i < rhs.i;
    }

    ostream& operator<<(ostream& out, const C& c) {
     out << "c" << c.i;
     return out;
    }
    // notice that ostream_iterator<C> is able to use this op<<,
    // so the copy(...) lines all compile in _tmain().

    namespace N { // (*)
    // without putting ContainerFront into namespace N
    // the code will compile.

    template<typename T> struct ContainerFront
    {
     typedef vector<T> Container;
     Container& m_rContainer;
     ContainerFront(Container& container):m_rContainer(container) {}

     T get(int i) const { return m_rContainer[i]; }
     void set(int i, const T& value) const { m_rContainer[i] = value; }

     struct item_proxy
     {
     public:

    // the reason for this value placeholder / reference thing
    // is not important now... but there is one. :)

      item_proxy() {} // value placeholder

      explicit item_proxy(const T& value):
       m_isReference(false), m_value(value) {}
        // value placeholder

      item_proxy(ContainerFront* pContainerFront, int index):
       m_isReference(true), m_pContainerFront(pContainerFront),
       m_index(index)
       {}
        // reference

      item_proxy(const item_proxy &rhs):
       m_isReference(false),
       m_value(static_cast<T>(rhs))
       {}
        // value placeholder

      operator T() const { // (*)
       return m_isReference ?
        m_pContainerFront->get(m_index) : m_value;
      }//operator T() const

      item_proxy& operator=(const T &value) {
       m_isReference ?
        m_pContainerFront->set(m_index, value)
        :
        m_value = value;
       return *this;
      }

      item_proxy& operator=(const item_proxy &rhs) {
       return (*this = static_cast<T>(rhs));
      }
     protected:
      bool m_isReference;
      ContainerFront *m_pContainerFront;
      int m_index;
            T m_value;
     };//struct item_proxy

     class iterator :
      public iterator_facade< iterator, T,
       std::random_access_iterator_tag, item_proxy >

    // never mind if you don't know iterator_facade.
    // the main point is that it uses the methods defined in the
    // private section to define a standard iterator interface
    // for this class.

     {
     public:
      iterator(ContainerFront* pContainerFront, int i):
       m_pContainerFront(pContainerFront), m_index(i) {}

      iterator():m_pContainerFront(0) {}

     private:
      friend class iterator_core_access;

      void increment() { ++m_index; }
      void decrement() { --m_index; }
      void advance(difference_type n) { m_index += (int)n; }

      difference_type distance_to(const iterator &rhs) const
      {
       return rhs.m_index - m_index;
      }

      bool equal(const iterator &rhs) const {
       return m_index == rhs.m_index;
      }

      reference dereference() const {
    // reference: typedef for item_proxy
       return item_proxy(m_pContainerFront, m_index);
      }

      ContainerFront* m_pContainerFront;
      int m_index;
     };//class iterator

     iterator begin() { return iterator(this, 0); }

     iterator end() {
      return iterator(this, (int)m_rContainer.size());
     }

    };//template<typename T> struct ContainerFront

    }//namespace N

    using namespace N;

    namespace M {

    template<typename TIterator>
    void f(TIterator it1, TIterator it2) {
     while (it1 < it2
      && !(*(it2 - 1) < *it2)
      && !(*it2 < *(it2 - 1)))
      --it2;
    // The compiler reports error for a line exactly equivalent to this
    // while compiling std::sort
    // This here compiles, however.
    // This function itself makes no sense, I just copied out the
    // line on which the compiler stumbles.
    }

    }//namespace M

    using namespace M;

    int _tmain(int argc, _TCHAR* argv[])
    {
    // test C:
     C ic[] = {10,9,8,7,6,5,4,3,2,1};
     vector<C> v(ic, ic+10);
     copy(v.begin(), v.end(), ostream_iterator<C>(cout, " "));
     cout << endl;

     sort(v.begin(), v.end());
     copy(v.begin(), v.end(), ostream_iterator<C>(cout, " "));
     cout << endl;

    // test ContainerFront:
     cout << endl;
     vector<C> vec(v.rbegin(), v.rend());
     ContainerFront<C> cf(vec);
     copy(v.rbegin(), v.rend(), cf.begin());
     copy(cf.begin(), cf.end(), ostream_iterator<C>(cout, " "));
      // (*) - here operator<< is used with no problem
     cout << endl;

     f(cf.begin(), cf.end());
     sort(cf.begin(), cf.end()); // compile error (*)
         // cannot find operator<
     copy(cf.begin(), cf.end(), ostream_iterator<C>(cout, " "));
     cout << endl;

     return 0;
    }

    // Thank you for reading through the whole thing. You must be very patient!


  • Next message: Michael T. Pudelko: "Re: Problems importing DLL"

    Relevant Pages