Re: Index a #define string
From: Paul Mensonides (leavings_at_comcast.net)
Date: 04/18/04
- Next message: Christopher Benson-Manica: "Re: The Gist of Object Oriented Programming"
- Previous message: thp_at_cs.ucr.edu: "Re: (i++ * i++)"
- In reply to: David Harmon: "Re: Index a #define string"
- Next in thread: Ioannis Vranos: "Re: Index a #define string"
- Reply: Ioannis Vranos: "Re: Index a #define string"
- Reply: David Harmon: "Re: Index a #define string"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Date: Sun, 18 Apr 2004 13:55:36 -0700
"David Harmon" <source@netcom.com> wrote in message
news:40d1cdf6.227441193@news.west.earthlink.net...
> On Sat, 17 Apr 2004 21:07:07 -0700 in comp.lang.c++, "Paul Mensonides"
> <leavings@comcast.net> wrote,
> >"Ioannis Vranos" <ivr@guesswh.at.emails.ru> wrote in message
> >
> >> With only few exceptions like inclusion guards, you can do whatever you can
> >> do with macros with templates. So what remains at the end are the dangerous
> >> uses.
> >
> >No, you can't. For instance, you cannot generate the source code of
templates
> >with templates, but you can with macros. You cannot generate a set of
typesafe
> >overloaded functions with arity ranging from zero to any conceivable number
of
> >parameters with templates, but you can with macros.
>
> Oh, that is all sophistry. You are saying basically, that you cannot
> use templates in the identical fashion that you use macros. Well, so
> what? The point is that you can accomplish the reasonable purpose
> formerly served by macros, with templates, consts, and other C++
> constructs that offer the advantages of being integrated with the
> language. That you cannot perform exactly the same gyrations on the way
> to getting there is not a bug, it's a feature.
No, it isn't sophistry. It's simply a gross reduction of solutions to issues of
which you apparently have no conception. I'm not talking about generating
functions or classes with varying types, and I'm certainly not advocating that
macros be used for such a purpose without a really good reason--that is what
templates are for. I'm talking about generating source code, be it templates or
overloaded functions or whatever (a lexical analyzer, perhaps) that is
impossible to achieve otherwise without an external code generator or with
excessive manual copying. The first requires another build step--which is
terrible in a library context--and the second dramatically increases the number
of maintenance points.
The point is that you can accomplish many *but by no means all* purposes
formally served by macros. I'm not disagreeing that there are better solutions
to many things that macros were used for at one time. It isn't a question of
getting to the same place a different way; instead, it is that the destination
is quite different. One way to look at it is that the preprocessor is to
templates as templates are to classes and functions. (That certainly doesn't
summarize the entire field, but it does summarize a large portion of it.)
Regarding your "bug/feature" statement... You are certainly correct that
templates are a great feature for what they are intended to do. The same
extends to constant variables vs. macros, but to a slightly lesser degree. I'm
not arguing that, and I never will. What I am arguing is that statements such
as "macros are evil" or "macros are inherently dangerous" (which are both common
statements) are prejudicial generalizations that simply aren't true. Macros are
not evil, certain usages of them are. Macros are not inherently dangerous,
certain uses of them are. That is no different than any other language feature
or intersection of features. The only difference is that many have been too
brainwashed by statements like the above to investigate the cause-and-effect of
feature intersections within the preprocessor (within macro expansion in
particular) and feature intersections between the preprocessor and the language
proper--like they have with the underlying language.
As an aside, the core language is no more protected from name clashes than the
preprocessor. Namespaces serve to classify and organize names, but they do not,
at a language level, protect them. The only things that stop name collision are
1) utilize existing and well-known idioms and techniques such as documenting
which namespaces are considered "owned" by a component or library and 2)
decrease the likelihood of a clash by effectively extending the name (i.e.
namespace qualification). For example, say some component/library has this code
in a header:
// library.h
namespace library {
struct abc {
operator int() const {
return 0;
}
};
}
And then some other library or project header has this code:
namespace library {
const struct {
int operator()() const {
return 1;
}
} abc = { };
}
The above two declarations can silently coexist, but the expression "abc()" can
silently mean a different thing depending on where it is used. Obviously, a
scenario such as the above is very unlikely, but the point remains--the language
does not protect against name clashes in general. Only good conventions like
"don't use the same namespace" protect code against such collisions. The same
is true for macros, but instead of having an explicit qualification syntax, you
have prefixing (such as LIBRARY_ABC) (or suffixing) and good conventions like
"use all uppercase names for macros and only for macros". Together, it
accomplishes the same thing--protection against name interference--as the use of
namespaces and the accompanying conventions that are relied on by namespace
authors and users. That is certainly not the only sort of problem that the use
of macros can cause, but it is a major one. There are many other examples,
similar to the above, that illustrate the lack of true name encapsulation in the
core language. Most of the time such a name clash isn't silent--just as it
usually isn't with macros. (In fact, silent changes (i.e. the *really* hard
ones to deal with) are rare even without the application of any convention
whatsoever.) Nevertheless, the problems that can surface can be extremely
roundabout--such as dealing with subtle POI issues in different translation
units--where a diagnostic is not required by standard. Consider, for example,
what can the following can do, in the right circumstances, to constant
expressions involving enumerations (e.g. template metaprogramming that doesn't
use static const):
template<class T, class U> T operator+(T, U);
It once again shows that names are not encapsulated--only organized, and why
convention is the true means of encapsulation against name clash. A reasonable
convention to handle the above would be "do not declare completely generic
operator overloads".
Regards,
Paul Mensonides
- Next message: Christopher Benson-Manica: "Re: The Gist of Object Oriented Programming"
- Previous message: thp_at_cs.ucr.edu: "Re: (i++ * i++)"
- In reply to: David Harmon: "Re: Index a #define string"
- Next in thread: Ioannis Vranos: "Re: Index a #define string"
- Reply: Ioannis Vranos: "Re: Index a #define string"
- Reply: David Harmon: "Re: Index a #define string"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Relevant Pages
|