Topic: Problem with using typedef in a namespace


Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/05/21
Raw View
In article <926546143.23350.0.nnrp-12.9e98df50@news.demon.co.uk>, Kit
Smithers <kitsnews@kits.demon.co.uk> writes
>Anyway to finally get to my point. I feel that the standard doesnt provide a
>suitable way of allowing you to create "copies" of other types. The typedef
>provides a form of naming alias which doesnt seem much better than doing a
>#define.

struct MyType: public Yourtype {
};

Doesn't this meet your needs?

And if you are concerned with a built-in type:

class MyInt {
        int value;
public:
        MyInt(int i = 0): value(i){}
        operator int (){ return value; }
};

would seem to provide the basis for what you want to do.

Francis Glassborow      Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Kit Smithers" <kitsnews@kits.demon.co.uk>
Date: 1999/05/13
Raw View
Joerg Barfurth wrote in message <37321825.7EFA9645@vossnet.de>...
>
>Kit Smithers wrote:
>>
>> I'm having trouble understanding why the following code produces
different
>> results.

(snipped code showing typedef producing correct but for me surprising
results when used in a namespace)

>In namespace ABC (and thereby in myFunc) both operators from namespace CSS
>can't be found by unqualified name lookup, nor are they explicitly
qualified
>in your code (you can't write gstream CSS::<< mystring anyways). So if any
of
>them can still be found, it has to be by argument dependent (or 'Koenig')
name
>lookup. Basically this means that, in addition to the local scope, the
>namespaces where the arguments' types are defined are also searched for
>matching 'candidate' function declarations.
>This is covered in the standard in section 4.3.2 [basic.lookup.koenig]. In
>paragraph 2 it reads:
>"For each argument type T in the function call, there is a set of zero or
more
>associated namespaces [...] to be considered. The set of namespaces [...]
is
>determined entirely by the types of the function arguments (...). TYPEDEF
>NAMES [...] DO NOT CONTIBUTE TO THIS SET." (emphasis added by me).
>This is in accordance with the semantics of typedef mentioned above
(referring
>to 7.1.3).


Thanks for the explanation. A number of people have pointed me towards the
argument dependent lookup rules and I know have a better understanding of
what I did wrong. My thanks to all of them.

My followup really relates to the problems that I feel exist with the
typedef keyword. I find that the resulting actions of doing a typedef dont
allow for the kind of flexibility that I would like. In this case I would
like to effectively produce a new "type" that is the same as another one but
to behave as if I had defined it myself.

Another example of why I find this troublesome is that you cant make a
forward declaration for something that is typedef'd eg.

// header file with forward declaration of MyClass
class MyClass;

// header file for MyClass which is actually typdef'd to MyOtherClass
class MyOtherClass {};
typedef MyOtherClass MyClass;

would cause the second header file to fail to compile (if preceeded by the
first) because I've previously declared MyClass as a class. I can easily
change the forward declaration header file to work.

And why do I want to do this? The reason is that I want to make use of a 3rd
party library within the library that I am building but I dont want to make
users of my library aware of this other library. Sometimes I just want them
to see my names (in my namespace) for the types in order to give me the
option at a later date of replacing the class with one of my own. I dont
want to wrap up the 3rd party class in all cases because of the work
involved - ideally I would do that but there are time constraints on
producing the work.

Anyway to finally get to my point. I feel that the standard doesnt provide a
suitable way of allowing you to create "copies" of other types. The typedef
provides a form of naming alias which doesnt seem much better than doing a
#define.

Conversely I suppose that the problem extends in the other way where
sometimes you want to make copies of types that arent "the same" eg:

typedef int Altitude;
typedef int Speed;

which would allow you to assign a Speed to Altitude with the potential for
disaster that could cause.

I'm aware of how to get around the problem above but I cant help feeling
that once again I'm being let down by the typedef keyword.

--
Kit Smithers
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Kit Smithers" <kitsnews@kits.demon.co.uk>
Date: 1999/05/06
Raw View
I'm having trouble understanding why the following code produces different
results.

It fails under g++ and vc++ although with slightly different errors. The
problem as I see it is that making a typedef in a namespace to a class
defined in the global namespace does not behave the same as a typedef to a
class in the same namespace. Not that there's any reason that it should. But
it makes seemingly identical function definitions produce different results.

Here's the code... the line that fails is near the end I've included a
comment with the error g++ gives.

#include <string>

class Byte_Stream_GLOBAL {};

namespace CSS {

class Byte_Stream_CSS {};

typedef Byte_Stream_GLOBAL ByteStreamG;
typedef Byte_Stream_CSS    ByteStreamC;

ByteStreamG& operator<<(ByteStreamG& into, const std::string& s);
ByteStreamC& operator<<(ByteStreamC& into, const std::string& s);

}

namespace ABC {

void myFunc(void)
{
    CSS::ByteStreamG gstream;
    CSS::ByteStreamC cstream;

    std::string mystring = "hello world";

    cstream << mystring;
    gstream << mystring;  // This line produces an error
 /*
 nameclash.cxx: In function `void myFunc()':
nameclash.cxx:35: no match for `::CSS::ByteStreamG & << string &'
C:\\CYGNUS\\CYGWIN~1\\H-I586~1\\BIN\\..\\lib\\gcc-lib\\i586-cygwin32\\egcs-2
.91.
57\\..\\..\\..\\..\\..\\include\\g++\\std/bastring.cc:469: candidates are:
opera
tor <<<char, string_char_traits<char>, alloc>(ostream &, const
basic_string<char
,string_char_traits<char>,__default_alloc_template<false,0> > &)
     */
}

}


The "work around"  - as in a work around my ignorance is to define the
function outside of the namespace as in:

CSS::ByteStreamG& operator<<(CSS::ByteStreamG& into, const std::string& s);

Which the compiler finds acceptable.

Can anyone give me an indication -- or which bit of the standard I should
read -- as to what's going on?

My thanks.

--
Kit Smithers
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Joerg Barfurth <jbarfurth@vossnet.de>
Date: 1999/05/07
Raw View
Kit Smithers wrote:
>
> I'm having trouble understanding why the following code produces different
> results.
>
> It fails under g++ and vc++ although with slightly different errors. The
> problem as I see it is that making a typedef in a namespace to a class
> defined in the global namespace does not behave the same as a typedef to a
> class in the same namespace. Not that there's any reason that it should. But
> it makes seemingly identical function definitions produce different results.

The typedefs behave identical. But still one (class-)type is defined in that
namespace, while the other is defined in global namespace. For elaboration,
see below.

> Here's the code... the line that fails is near the end I've included a
> comment with the error g++ gives.
>
> #include <string>
>
> class Byte_Stream_GLOBAL {};
>
> namespace CSS {
>
> class Byte_Stream_CSS {};
>
> typedef Byte_Stream_GLOBAL ByteStreamG;
> typedef Byte_Stream_CSS    ByteStreamC;
>
> ByteStreamG& operator<<(ByteStreamG& into, const std::string& s);
> ByteStreamC& operator<<(ByteStreamC& into, const std::string& s);
>
> }
>
> namespace ABC {
>
> void myFunc(void)
> {
>     CSS::ByteStreamG gstream;
>     CSS::ByteStreamC cstream;
>
>     std::string mystring = "hello world";
>
>     cstream << mystring;
>     gstream << mystring;  // This line produces an error
>  /*
>  nameclash.cxx: In function `void myFunc()':
> nameclash.cxx:35: no match for `::CSS::ByteStreamG & << string &'

It is correct, to see an error here, but this error message is IMHO
misleading:
The match needed is for ::Byte_Stream_GLOBAL & << ::std::string &.
A typedef name is just another name for a type (i.e it doesn't introduce a new
type. So the type of gstream actually is ::Byte_Stream_Global (see [7.1.3]
p.1). This should already be a hint at what's going on.

> C:\\CYGNUS\\CYGWIN~1\\H-I586~1\\BIN\\..\\lib\\gcc-lib\\i586-cygwin32\\egcs-2
> .91.
> 57\\..\\..\\..\\..\\..\\include\\g++\\std/bastring.cc:469: candidates are:
> opera
> tor <<<char, string_char_traits<char>, alloc>(ostream &, const
> basic_string<char
> ,string_char_traits<char>,__default_alloc_template<false,0> > &)
>      */
> }
>
> }
>
> The "work around"  - as in a work around my ignorance is to define the
> function outside of the namespace as in:
>
> CSS::ByteStreamG& operator<<(CSS::ByteStreamG& into, const std::string& s);

As you don't define "CSS::ByteStreamG& CSS::operator<<(CSS::ByteStreamG& into,
const std::string& s)" (actually you only show a declaration), this
declaration introduces a second operator function with this signature.
This declaration is not related to the one in namespace CSS (except that they
might clash when resolving overloads where both are in scope).

> Which the compiler finds acceptable.
Fine

> Can anyone give me an indication -- or which bit of the standard I should
> read -- as to what's going on?

In namespace ABC (and thereby in myFunc) both operators from namespace CSS
can't be found by unqualified name lookup, nor are they explicitly qualified
in your code (you can't write gstream CSS::<< mystring anyways). So if any of
them can still be found, it has to be by argument dependent (or 'Koenig') name
lookup. Basically this means that, in addition to the local scope, the
namespaces where the arguments' types are defined are also searched for
matching 'candidate' function declarations.
This is covered in the standard in section 4.3.2 [basic.lookup.koenig]. In
paragraph 2 it reads:
"For each argument type T in the function call, there is a set of zero or more
associated namespaces [...] to be considered. The set of namespaces [...] is
determined entirely by the types of the function arguments (...). TYPEDEF
NAMES [...] DO NOT CONTIBUTE TO THIS SET." (emphasis added by me).
This is in accordance with the semantics of typedef mentioned above (referring
to 7.1.3).

By this token, Koenig lookup finds CSS::operator<<(...) for
CSS::Byte_Stream_CSS (aka CSS::ByteStreamC), but not for ::Byte_Stream_GLOBAL
(aka CSS::ByteStreamG). Any operator<< declared at global scope (or in
namespace ::std, if ::std::string is the other argument's type) will be
considered as candidate functions for overload resolution (see [13.3.1]) in
the latter case.

HTH
-- J   rg Barfurth


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Martin von Loewis <loewis@informatik.hu-berlin.de>
Date: 1999/05/07
Raw View
"Kit Smithers" <kitsnews@kits.demon.co.uk> writes:

> Can anyone give me an indication -- or which bit of the standard I should
> read -- as to what's going on?

I recommend 3.4.2 "Argument=ADdependent name lookup". This is the
procedure commonly called "Koenig lookup". When the compiler searches
for operator<<, it normally wouldn't find your operators, since they
are in a namespace, and you have no using directives or the like.

With Koenig lookup, the compiler will also look into CSS when an
argument is of type Byte_Stream_CSS. For Byte_Stream_GLOBAL, it will
only look in the global namespace. The existence of typedefs doesn't
matter at all.

Hope this helps,
Martin
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]