Namespaces and lookup error.

Namespaces and lookup error.

Post by Dhru » Tue, 29 Jul 2003 02:11:18



#include <vector>
#include <deque>

namespace nstd {
template <class InputIterator, class OutputIterator>
OutputIterator copy (InputIterator first, InputIterator last, OutputIterator
result)
{
  while (first != last)
    {
      *result = *first;
      ++result; ++first;
    }

Quote:}

template <class T> class cheap_allocator;
// specialize for void:
template <> class cheap_allocator<void> {
public:
  typedef void*       pointer;
  typedef const void* const_pointer;
  //  reference-to-void members are impossible.
  typedef void  value_type;
  template <class U> struct rebind { typedef cheap_allocator<U> other; };

Quote:};

template <class T> class cheap_allocator {
public:
  typedef size_t    size_type;
  typedef ptrdiff_t difference_type;
  typedef T*        pointer;
  typedef const T*  const_pointer;
  typedef T&        reference;
  typedef const T&  const_reference;
  typedef T         value_type;
  template <class U> struct rebind { typedef cheap_allocator<U> other; };
  cheap_allocator() throw() { }
  cheap_allocator(size_type, size_type) throw() { }
  cheap_allocator(const cheap_allocator&) throw() { }
  template <class U> cheap_allocator(const cheap_allocator<U>&) throw() { }
  ~cheap_allocator() throw() { }
  pointer address (reference r) const { return &r; }
  const_pointer address (const_reference r) const { return &r; }
  pointer allocate(
                   size_type n, typename cheap_allocator<void>::const_pointer hint = 0)
  {
    return (T*)operator new (n*sizeof(T));
  }
  void deallocate(pointer p, size_type n)
  {
    operator delete (p);
  }
  size_type max_size() const throw() { return (--size_type())/sizeof(T); }
  void construct(pointer p, const T& val)
  {
    new (p) T(val);
    return p;
  }
  void destroy(pointer p)
  {
    p->~T();
  }

Quote:};
}

  int main () {

    std::vector<int, nstd::cheap_allocator<int> > iv;
    std::deque<int, nstd::cheap_allocator<int> > id;

//     std::vector<int, std::allocator<int> > iv;
//     std::deque<int, std::allocator<int> > id;

    for (int j = 0; j < 100; ++j) {
      for (int i = 0; i < 10000; ++i) {
        iv.push_back (i);
        id.push_back (i);
      }
    }

  }

Now, when, I comment out the containers that use nstd:: allocators, and
uncomment the ones that use standard allocators, it compiles just fine?
Why so? I'm using g++ 3.2. on RH9.

Regards,
-Dhruv.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

 
 
 

Namespaces and lookup error.

Post by Andy Sawye » Tue, 29 Jul 2003 08:34:56



 on 27 Jul 2003 13:11:18 -0400,


> Now, when, I comment out the containers that use nstd:: allocators, and
> uncomment the ones that use standard allocators, it compiles just fine?
> Why so? I'm using g++ 3.2. on RH9.

It might help if you tell us what the compilation problem actually is...

Regards,
 Andy S
--
"Light thinks it travels faster than anything but it is wrong. No matter
 how fast light travels it finds the darkness has always got there first,
 and is waiting for it."                  -- Terry Pratchett, Reaper Man

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

 
 
 

Namespaces and lookup error.

Post by Bo Persso » Tue, 29 Jul 2003 09:02:15



> #include <vector>
> #include <deque>

> namespace nstd {
> template <class InputIterator, class OutputIterator>
> OutputIterator copy (InputIterator first, InputIterator last,
OutputIterator
> result)
> {
>   while (first != last)
>     {
>       *result = *first;
>       ++result; ++first;
>     }
> }

> template <class T> class cheap_allocator;
> // specialize for void:
> template <> class cheap_allocator<void> {
> public:
>   typedef void*       pointer;
>   typedef const void* const_pointer;
>   //  reference-to-void members are impossible.
>   typedef void  value_type;
>   template <class U> struct rebind { typedef cheap_allocator<U>
other; };
> };

> template <class T> class cheap_allocator {
> public:
>   typedef size_t    size_type;
>   typedef ptrdiff_t difference_type;

These should probably be std::size_t and std::ptrdiff_t ?

- Show quoted text -

Quote:>   typedef T*        pointer;
>   typedef const T*  const_pointer;
>   typedef T&        reference;
>   typedef const T&  const_reference;
>   typedef T         value_type;
>   template <class U> struct rebind { typedef cheap_allocator<U>
other; };
>   cheap_allocator() throw() { }
>   cheap_allocator(size_type, size_type) throw() { }
>   cheap_allocator(const cheap_allocator&) throw() { }
>   template <class U> cheap_allocator(const cheap_allocator<U>&)
throw() { }
>   ~cheap_allocator() throw() { }
>   pointer address (reference r) const { return &r; }
>   const_pointer address (const_reference r) const { return &r; }
>   pointer allocate(
>    size_type n, typename cheap_allocator<void>::const_pointer hint =
0)
>   {
>     return (T*)operator new (n*sizeof(T));
>   }
>   void deallocate(pointer p, size_type n)
>   {
>     operator delete (p);
>   }
>   size_type max_size() const throw() { return

(--size_type())/sizeof(T); }

You cannot use operator-- on a temporary, you could try size_type(-1)
instead.

Or even better, std::numeric_limits<size_type>::max()

Quote:>   void construct(pointer p, const T& val)
>   {
>     new (p) T(val);
>     return p;

You cannot return anything if the function is declared with a void
return type.

- Show quoted text -

Quote:>   }
>   void destroy(pointer p)
>   {
>     p->~T();
>   }
> };

> }

>   int main () {

>     std::vector<int, nstd::cheap_allocator<int> > iv;
>     std::deque<int, nstd::cheap_allocator<int> > id;

> //     std::vector<int, std::allocator<int> > iv;
> //     std::deque<int, std::allocator<int> > id;

>     for (int j = 0; j < 100; ++j) {
>       for (int i = 0; i < 10000; ++i) {
> iv.push_back (i);
> id.push_back (i);
>       }
>     }

>   }

> Now, when, I comment out the containers that use nstd:: allocators,
and
> uncomment the ones that use standard allocators, it compiles just
fine?
> Why so? I'm using g++ 3.2. on RH9.

Except for a few "unused parameters", it then compiles with MSVC 7.1

Bo Persson

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

 
 
 

Namespaces and lookup error.

Post by Siemel Nara » Tue, 29 Jul 2003 09:04:39


Your program compiled fine on Borland 6 and debugging showed it call your
cheap_allocator<int>::allocate.  It also compiled fine on g++ 2.95.

Then looking at the template definition of cheap_allocator<T> and the
specialization for T==void it seems your order is wrong.  Define the general
cheap_allocator first then specialize, like this:

template <class T> class cheap_allocator; // not necessary
template <class T> class cheap_allocator { ... };
template <> class cheap_allocator<void> { ... };

Then in the line I got an error

  pointer allocate(
   size_type n, typename cheap_allocator<void>::const_pointer hint = 0)

[C++ Error] Unit1.cpp(40): E2089 Identifier 'const_pointer' cannot have a
type qualifier

Seems class cheap_allocator<void> is not a template, so you cannot use the
typename keyword.  So I remove the typename.  On Borland there is still one
more error, and on g++ there are countless errors.

[C++ Error] Unit1.cpp(40): E2293 ) expected

My theory is that when the compiler encounters
cheap_allocator<void>::const_pointer it tries to instantiate class
cheap_allocator<void> and fails because there things like
cheap_allocator<void>::reference are errors.  So you can try this way:

template <class T> class cheap_allocator; // not necessary
template <class T> class cheap_allocator {
....
  pointer allocate(
   size_type n, const void * hint = 0);

Quote:};

template <> class cheap_allocator<void> { ... }
template <class T>
inline
typename cheap_allocator<T>::pointer
cheap_allocator<T>::allocate(
   size_type n, /*typename*/ cheap_allocator<void>::const_pointer hint)
  {
    return (T*)operator new (n*sizeof(T));
  }

BTW, for the cast line I recommend

    return static_cast<T*>(operator new (n*sizeof(T)));

--
+++++++++++
Siemel Naran

Quote:> #include <vector>
> #include <deque>

> namespace nstd {
> template <class InputIterator, class OutputIterator>
> OutputIterator copy (InputIterator first, InputIterator last,
OutputIterator
> result)
> {
>   while (first != last)
>     {
>       *result = *first;
>       ++result; ++first;
>     }
> }

> template <class T> class cheap_allocator;
> // specialize for void:
> template <> class cheap_allocator<void> {
> public:
>   typedef void*       pointer;
>   typedef const void* const_pointer;
>   //  reference-to-void members are impossible.
>   typedef void  value_type;
>   template <class U> struct rebind { typedef cheap_allocator<U> other; };
> };

> template <class T> class cheap_allocator {
> public:
>   typedef size_t    size_type;
>   typedef ptrdiff_t difference_type;
>   typedef T*        pointer;
>   typedef const T*  const_pointer;
>   typedef T&        reference;
>   typedef const T&  const_reference;
>   typedef T         value_type;
>   template <class U> struct rebind { typedef cheap_allocator<U> other; };
>   cheap_allocator() throw() { }
>   cheap_allocator(size_type, size_type) throw() { }
>   cheap_allocator(const cheap_allocator&) throw() { }
>   template <class U> cheap_allocator(const cheap_allocator<U>&) throw()
{ }
>   ~cheap_allocator() throw() { }
>   pointer address (reference r) const { return &r; }
>   const_pointer address (const_reference r) const { return &r; }
>   pointer allocate(
>    size_type n, typename cheap_allocator<void>::const_pointer hint = 0)
>   {
>     return (T*)operator new (n*sizeof(T));
>   }
>   void deallocate(pointer p, size_type n)
>   {
>     operator delete (p);
>   }
>   size_type max_size() const throw() { return (--size_type())/sizeof(T); }
>   void construct(pointer p, const T& val)
>   {
>     new (p) T(val);
>     return p;
>   }
>   void destroy(pointer p)
>   {
>     p->~T();
>   }
> };

> }

>   int main () {

>     std::vector<int, nstd::cheap_allocator<int> > iv;
>     std::deque<int, nstd::cheap_allocator<int> > id;

> //     std::vector<int, std::allocator<int> > iv;
> //     std::deque<int, std::allocator<int> > id;

>     for (int j = 0; j < 100; ++j) {
>       for (int i = 0; i < 10000; ++i) {
> iv.push_back (i);
> id.push_back (i);
>       }
>     }

>   }

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
 
 
 

Namespaces and lookup error.

Post by Dhru » Tue, 29 Jul 2003 18:54:38



 >  on 27 Jul 2003 13:11:18 -0400,

 >
 >> Now, when, I comment out the containers that use nstd:: allocators, and
 >> uncomment the ones that use standard allocators, it compiles just fine?
 >> Why so? I'm using g++ 3.2. on RH9.
 >
 > It might help if you tell us what the compilation problem actually is...
 >

The problem is that (apart form all those the Bo Persson corrected) when I
use cheap_allocator, which is inside namespace nstd::, the compiler
complains of ambiguity of the copy function, whereas if I use an allocator
within std:: namespace, it does not.

Regards,
-Dhruv.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

 
 
 

Namespaces and lookup error.

Post by David Abraham » Wed, 30 Jul 2003 06:43:26



> Now, when, I comment out the containers that use nstd:: allocators, and
> uncomment the ones that use standard allocators, it compiles just fine?
> Why so? I'm using g++ 3.2. on RH9.

Because the standard library that ships with G++ calls all of its own
public functions (e.g. std::copy) without using the std::
qualification, so argument-dependent-lookup finds your nstd::copy as
well as the one in std::.  This is, IMO, a bug, and I hope that they
will fix it.  I suggest you put the allocator and copy in separate
namespaces.  You can bring them together with a using-directive so
that your client code still compiles and it won't stimulate this
problem.

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

 
 
 

Namespaces and lookup error.

Post by Richard Smit » Wed, 30 Jul 2003 06:48:21



> The problem is that (apart form all those the Bo Persson corrected) when I
> use cheap_allocator, which is inside namespace nstd::, the compiler
> complains of ambiguity of the copy function, whereas if I use an allocator
> within std:: namespace, it does not.

I'm guessing that the ambiguous call to copy is from
unqualified name somewhere within the STL?  If so, this is
because of the way name lookup works in templates.  The
problem stems from the fact that nstd::copy is being found
by ADL (it is in the associated namespace of the allocator
template parameter).  In addition std::copy is being found
by ordinary lookup (and quite possibly ADL as well).  As the
two functions have identical signatures, neither is a better
match than the other, and so the call is ambiguous.

As I recall, there is a DR stating that STL implementations
must not call functions via unqualified dependent names when
there is the possibility of ADL causing another name to be
found.  If this is correct, then your STL is wrong.
Unfortunately, I can't find such a DR, and wonder whether I
might have imagined it entirely!

One way of solving the problem is to get rid of your copy
function.  Why is it there anyway?  It is exactly the same
as std::copy, except that std::copy may well be better
optimised is certain cases.  If you remove, rename or change
the signature of your copy function, the problem will
probaqbly go away.

--
Richard Smith

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

 
 
 

Namespaces and lookup error.

Post by Dhru » Wed, 30 Jul 2003 19:23:47


[snip]......

 >
 > Because the standard library that ships with G++ calls all of its own
 > public functions (e.g. std::copy) without using the std::
 > qualification, so argument-dependent-lookup finds your nstd::copy as
 > well as the one in std::.  This is, IMO, a bug, and I hope that they
 > will fix it.  I suggest you put the allocator and copy in separate
 > namespaces.  You can bring them together with a using-directive so
 > that your client code still compiles and it won't stimulate this
 > problem.

Ok, thanks, I see you have a thread on this on bugzilla :-)

-Dhruv.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

 
 
 

Namespaces and lookup error.

Post by Dhru » Wed, 30 Jul 2003 19:24:22


 >
[snip].......

 > As I recall, there is a DR stating that STL implementations
 > must not call functions via unqualified dependent names when
 > there is the possibility of ADL causing another name to be
 > found.  If this is correct, then your STL is wrong.
 > Unfortunately, I can't find such a DR, and wonder whether I
 > might have imagined it entirely!
 >
 > One way of solving the problem is to get rid of your copy
 > function.  Why is it there anyway?  It is exactly the same
 > as std::copy, except that std::copy may well be better
 > optimised is certain cases.  If you remove, rename or change
 > the signature of your copy function, the problem will
 > probaqbly go away.
 >

Ok, so if they have to explicitly put the std:: qualification, say inside
the vector class, it is using copy. Right now, it has code something like:

copy (...);

So, should this be changed to std::copy (...) //assuming that vector
//itself resides in std::

OR:

::std::copy (...)  //Meaning that clients cannot do something like:

namespace foo {
#include <vector>

Quote:}

using foo::std::vector;

int main () { }

Regards,
-Dhruv.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

 
 
 

Namespaces and lookup error.

Post by Richard Smit » Fri, 01 Aug 2003 09:16:04



> Right now, it has code something like:

> copy (...);

I guessed as much.

Quote:> So, should this be changed to std::copy (...) //assuming that vector
> //itself resides in std::

I'd be somewhat hesitant about changing this.  If you're
using a moderately recent STL, I'm expect the writers of the
STL will have been aware of this issue and will have
considered the relative merits of qualified and unqualified
names.  By changing the way it is done, you risk subtly
breaking your STL.

Your solution really should be to remove, rename or change
the signature of your copy function.  It does nothing that
the version in namespace std doesn't do, and the version in
namespace std may well make additional optimisations (e.g.
calling memcpy when allowed).

Quote:> OR:

> ::std::copy (...)  //Meaning that clients cannot do something like:

I've never really seen the advantage to this style when you
are already in namespace std.  Having said that, I know that
Boost sometimes uses this style, and I doubt they would do
it without a good reason.

Quote:> namespace foo {
> #include <vector>

You are not allowed to do this, and you will almost
certainly find things break horribly if you try.

--
Richard Smith

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

 
 
 

Namespaces and lookup error.

Post by Bo Persso » Sat, 02 Aug 2003 10:59:06



> > OR:

> > ::std::copy (...)  //Meaning that clients cannot do something
like:

> I've never really seen the advantage to this style when you
> are already in namespace std.  Having said that, I know that
> Boost sometimes uses this style, and I doubt they would do
> it without a good reason.

They have *a* reason - some Borland compilers handle templates better
for X< ::std::whatever >, so they use ::std:: everywhere to be on the
safe side.

If it is a *good* reason is debatable.  :-)

Bo Persson

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

 
 
 

Namespaces and lookup error.

Post by Dhru » Sun, 03 Aug 2003 02:08:14




>> > OR:

>> > ::std::copy (...)  //Meaning that clients cannot do something
> like:

>> I've never really seen the advantage to this style when you
>> are already in namespace std.  Having said that, I know that
>> Boost sometimes uses this style, and I doubt they would do
>> it without a good reason.

> They have *a* reason - some Borland compilers handle templates better
> for X< ::std::whatever >, so they use ::std:: everywhere to be on the
> safe side.

> If it is a *good* reason is debatable.  :-)

What I had in mind was that they use ::std::whatever, because I assumed
that <vector> could be #included inside another namesapce, and then inside
vector, if you use std::copy(), it might not find it, so better to tell it
to start form global scope, go down to std:: and then search for copy(),
but then again, as Richard Smith pointed out, it will no doubt lead to
100000's of errors while compiling. Then again, it is possible that
<vector> does #include <algorithm>, (of course it does), so std::whatever
would in fact be the correct alternative.

Regards,
-Dhruv.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

 
 
 

1. Namespace lookup bug?

I have the following, which exhibits surprising recursive behavior.

//----------------- Kernel.h
namespace Kernel
{
    class Class
    {
        int i;
    public:
        Class(int ii) : i(i) {}

        Class &operator=(Class const &c)
        {
            i = c.i;
            return *this;
        }
    };

//--------------------- User.cpp
#include "Kernel.h"

namespace User
{
    class Class : public Kernel::Class
    {
        typedef Kernel::Class Base;
        int j;

    public:
        Class(int ii, int jj) : Base(ii), j(jj) {}

        Class &operator=(Class const &c)
        {
            Base::operator=(c); //***** recursion!!!
            j = c.j;
            return *this;
        }
    };

int main()
{
    using namespace User;

    Class c1(1, 2);
    Class c2(3, 4);

    c1 = c2;
    return 0;

It seems the compiler cannot resolve names over namespaces correctly.
The Base::operator=(s) call recurses to User::Class::operator=() and
never reaches Kernel::Class::operator=(), as it should (shouldn't it?).
If I change the name of Kernel::Class to something other than Class, it
works as expected. I thought one of the reasons for namespaces was
exactly to be able to use the same names without conflicts.
--
Martin Fabian                         http://www.s2.chalmers.se/~fabian/
                                                                      --
"Cheer up. It may never happen"                          (Edina Monsoon)

        /* Remove NOSPAM from reply-to address to mail me */


      [ about comp.lang.c++.moderated. First time posters: do this! ]

2. InstallConsole etc. link error in Mach-O

3. Namespaces and Lookup

4. Early releases of Psion5

5. namespace lookup question

6. Instant Messenger-like window

7. issue with namespaces and operator lookup

8. Cross Compilers

9. Pointers to functions, namespaces, Koenig lookup

10. HRESULT Plus Error Lookup Tool update ...

11. HELP !!! async lookup error!

12. error: SWbemLocator: Invalid namespace