Index a #define string

I

Ioannis Vranos

And some nicest alternatives:
#define NULL 0


const int NULL=0;

#define offsetof(s,m) (size_t)&(((s *)0)->m)


That appears to not work. You cast 0 to a struct/class pointer of s *, you
dereference that null pointer it to access a data member m which is illegal,
and then you get its address and cast it to size_t.






Ioannis Vranos
 
J

Julie

Ioannis said:
And some nicest alternatives:


const int NULL=0;

How about some justification as to why const is 'nicer' than #define, other
than rhetoric.
That appears to not work. You cast 0 to a struct/class pointer of s *, you
dereference that null pointer it to access a data member m which is illegal,
and then you get its address and cast it to size_t.

This is how it is implemented in my stddef.h -- the particulars are
implementation-defined, however the behavior is well-defined.

I've provided two examples of macros that satisfy his question.
 
I

Ioannis Vranos

Julie said:
How about some justification as to why const is 'nicer' than #define, other
than rhetoric.



The C++ Programming Language" 3rd Edition or Special Edition by Bjarne
Stroustrup (the creator of C++), page 88:


5.1.1 Zero

Zero (0) is an int. Because of standard conversions (§C.6.2.3), 0 can be
used as a constant of any integral (§4.1.1), floating point, pointer, or
pointer to member type. The type of zero will be determined by context. Zero
will typically (but not necessarily) be represented by the bit pattern
all-zeros of the appropriate size.

No object is allocated with the address 0. Consequently, 0 acts as a pointer
literal, indicating that a pointer doesn't refer to an object.

In C, it has been popular to define a macro NULL to represent the zero
pointer. Because of C++'s tighter type checking, the use of plain 0, rather
than any suggested NULL macro, leads to fewer problems. If you feel you must
define NULL, use

const int NULL = 0;

The const qualifier (§5.4) prevents accidental redefinition of NULL and
ensures that NULL can be used where a constant is required.



This is how it is implemented in my stddef.h -- the particulars are
implementation-defined, however the behavior is well-defined.


That's a nice detail to quibble about.

As all know the C-style cast has also an equally dangerous equivalent.

If A, B two types:


(A)B is equivalent to A(B). A lame example:


char x=(char)5;

char x=char(5);



So the above thing does id equivalent to:

#define offsetof(s,m) (size_t)&((s *(0))->m)


It creates an s * pointer variable initialised to 0 and then accesses the m
data member. However the behaviour of both these is very system specific
*and* undefined.

I've provided two examples of macros that satisfy his question.



And yours above is not evil?







Ioannis Vranos
 
J

Julie

Ioannis said:
That's a nice detail to quibble about.

Not quibbling about.

Take a look at the standard library regarding offsetof. The behavior is well
defined. How it is implemented, is implementation defined.

Forget about the actual implementation that I posted for a minute, and consider
the macro behavior. It is useful, well-defined, and a valuable component of
the standard library, and it is a macro.

I've answered the PP's question.
And yours above is not evil?

It isn't mine, but an example of a useful and beneficial macro.

The notion that "all macros are bad" is more dangerous than the potential
misuse of macros.

Chew on that for a while, once you get out of the box.

end.
 
K

Kevin Goodsell

Julie said:
This is how it is implemented in my stddef.h -- the particulars are
implementation-defined, however the behavior is well-defined.

You can't get well-defined out of implementation-defined. The best you
can hope for is more implementation defined.

However, in this case there is no implementation-defined behavior. It is
completely undefined.

-Kevin
 
I

Ioannis Vranos

Julie said:
Not quibbling about.

Take a look at the standard library regarding offsetof. The behavior is well
defined. How it is implemented, is implementation defined.

Forget about the actual implementation that I posted for a minute, and consider
the macro behavior. It is useful, well-defined, and a valuable component of
the standard library, and it is a macro.


"Well-defined" and "implementation-defined" are different in ISO C++
terminology.

We can't discuss about implementation-defined programming. One could provide
a function, template function or some other interface and the implementation
in asm. When we say avoid the use of macros, is because the use of macros is
inherently dangerous, it may behave in an unexpected way, and bugs caused by
macro substitution of a macro defined in a header file which used in another
header file, which is used in our code are of the most difficult to trace.

C++ provides a superior alternative to macros (and void *s by the way) ,
templates. They are compile time checked and type safe.

The notion that "all macros are bad" is more dangerous than the potential
misuse of macros.


Well it is apparent that we will stick to our own opinions.

Chew on that for a while, once you get out of the box.


I am not in the box, i am in the hug of my LCD monitor. :)






Ioannis Vranos
 
J

Julie

Kevin said:
You can't get well-defined out of implementation-defined. The best you
can hope for is more implementation defined.

However, in this case there is no implementation-defined behavior. It is
completely undefined.

When you pick pieces out of context, you can make any argument that you want.

I said that the _particulars_ are implementation defined (meaning the
underlying implementation), the _behavior_ is well defined.

Contrary to your belief, this is the case, and is entirely possible.

The previous poster requested an example of a 'non-evil' macro, and I provided
that.

As I said: The notion that "all macros are bad" is more dangerous than the
potential
misuse of macros.
 
K

Kevin Goodsell

Julie said:
When you pick pieces out of context, you can make any argument that you want.

I said that the _particulars_ are implementation defined (meaning the
underlying implementation), the _behavior_ is well defined.

If you defined that macro yourself and used it, the behavior would NOT
be defined. You are free to use the library-supplied 'offsetof' macro,
and it will be well-defined, but that's not the same. An implementation
would be perfectly within its rights to (for example) crash on your
macro, even if it's identical to the standard library version.
Contrary to your belief, this is the case, and is entirely possible.

If you rely on implementation-defined behavior, you can't do better than
implementation-defined. But that's not particularly relevant, since
there was no implementation-defined behavior in the example.
The previous poster requested an example of a 'non-evil' macro, and I provided
that.

'Evil' is a technical term in C++ circles. It doesn't mean "not to be
used under any circumstances". This is in the FAQ.

-Kevin
 
J

Julie

Kevin said:
If you defined that macro yourself and used it, the behavior would NOT
be defined. You are free to use the library-supplied 'offsetof' macro,
and it will be well-defined, but that's not the same. An implementation
would be perfectly within its rights to (for example) crash on your
macro, even if it's identical to the standard library version.


If you rely on implementation-defined behavior, you can't do better than
implementation-defined. But that's not particularly relevant, since
there was no implementation-defined behavior in the example.


'Evil' is a technical term in C++ circles. It doesn't mean "not to be
used under any circumstances". This is in the FAQ.

So what is your point to all of your responses w/ respect to the previous
poster's question and my response???

Do you agree that the offsetof() macro is an example of a 'non-evil' macro or
not?
 
D

David Harmon

On Sat, 17 Apr 2004 14:54:12 -0600 in comp.lang.c++, Julie
Do you agree that the offsetof() macro is an example of a 'non-evil' macro or
not?

It is very nasty in both intent and action. I think it would not exist
in C++ except for the need for backwards C compatibility.

In intent, it breaks encapsulation and encourages dependence on the
low-level layout and implementation of objects. Depend only upon the
classes' public interface. Use "pointer-to-member" when called for.

In action, it relies on non-portable tricks and cannot be defined within
standard C++. Or even C, I think, which is probably why it is in the
library instead of expecting self-abusers to supply their own.
 
P

Paul Mensonides

Ioannis Vranos said:
When we say avoid the use of macros, is because the use of macros is
inherently dangerous,

If you're going to make unilateral statements such as this, you need to actually
back it up with specifics instead of repeating prejudicial generalizations.
Macros are *not* inherently dangerous. Certain *uses* of macros are dangerous
and have other pitfalls, but by no means does this extend to the general notion
of macros. This extends to other constructs as well that have, at times, even
greater pitfalls in C++. The way to deal with these pitfalls is through idioms
and techniques that are not enforced by the language itself except in some cases
through diagnostics (and sometimes with no diagnostic required by the standard).
The preprocessor, and the macro mechanism in particular, is simply easier to
target as an isolated entity. The pronouncement that "macros are evil" is
merely an act of people being to lazy to define exactly what sorts of usages are
or are not evil with respect to macros. It is as ridiculous as saying that
templates are evil because undetected POI issues exist.
it may behave in an unexpected way, and bugs caused by
macro substitution of a macro defined in a header file which used in another
header file, which is used in our code are of the most difficult to trace.

C++ provides a superior alternative to macros (and void *s by the way) ,
templates. They are compile time checked and type safe.

Here your making another gross oversimplification. C++ provides a superior
alternative to using macros to define type/value generic constructs (such as
classes and functions) and inline functions (and sometimes constants). That
doesn't even come close to covering the range of uses of macros.

I totally agree with this. Specifically, notions like the above are dangerous
because they show a lack of understanding and thought about when and where which
tool should be applied. It shows a serious lack of lateral thinking and logical
deduction.
Well it is apparent that we will stick to our own opinions.




I am not in the box, i am in the hug of my LCD monitor. :)

:)

A statement like "macros are inherently dangerous" comes straight out of the
box. Consider Boost, which contains a great deal of out-of-the-box thinking
resulting in some incredible libraries that push the boundaries of all
previously existing design technique. And then consider further, that many of
those libraries are generated *with macros that have never caused a name clash
despite the relatively widespread use of Boost*. I'm not saying that macros are
the end-all-and-be-all, and I'm not saying that many uses (if not *most* uses in
practice) are not dangerous. What I am saying is that there are both good uses
and bad uses--just like with every other language feature or intersection of
features. Anything else is the result of people being too lazy to actually pin
down the problems or naivety caused by blind application of guidelines that are
themselves a product of previous laziness.

Regards,
Paul Mensonides
 
I

Ioannis Vranos

Paul Mensonides said:
If you're going to make unilateral statements such as this, you need to actually
back it up with specifics instead of repeating prejudicial generalizations.
Macros are *not* inherently dangerous. Certain *uses* of macros are dangerous
and have other pitfalls, but by no means does this extend to the general notion
of macros. This extends to other constructs as well that have, at times, even
greater pitfalls in C++. The way to deal with these pitfalls is through idioms
and techniques that are not enforced by the language itself except in some cases
through diagnostics (and sometimes with no diagnostic required by the standard).
The preprocessor, and the macro mechanism in particular, is simply easier to
target as an isolated entity. The pronouncement that "macros are evil" is
merely an act of people being to lazy to define exactly what sorts of usages are
or are not evil with respect to macros. It is as ridiculous as saying that
templates are evil because undetected POI issues exist.


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.



Here your making another gross oversimplification. C++ provides a superior
alternative to using macros to define type/value generic constructs (such as
classes and functions) and inline functions (and sometimes constants). That
doesn't even come close to covering the range of uses of macros.


So do you think macros should be used in every day's code?


I totally agree with this. Specifically, notions like the above are dangerous
because they show a lack of understanding and thought about when and where which
tool should be applied. It shows a serious lack of lateral thinking and logical
deduction.


I never said that "macros are evil". But (obviously) in the contrary of you,
i consider a good practice to try avoid using macros as much as it is
possible.

A statement like "macros are inherently dangerous" comes straight out of the
box.


And also i never said the above. What i said is

"We must try to avoid using macros completely (mainly by using templates),
with very few exceptions that this can't be done (mainly the #ifndef
stuff)."

Consider Boost, which contains a great deal of out-of-the-box thinking
resulting in some incredible libraries that push the boundaries of all
previously existing design technique. And then consider further, that many of
those libraries are generated *with macros that have never caused a name clash
despite the relatively widespread use of Boost*. I'm not saying that macros are
the end-all-and-be-all, and I'm not saying that many uses (if not *most* uses in
practice) are not dangerous. What I am saying is that there are both good uses
and bad uses--just like with every other language feature or intersection of
features. Anything else is the result of people being too lazy to actually pin
down the problems or naivety caused by blind application of guidelines that are
themselves a product of previous laziness.


Well i agree. But i like to term the meaning of your phrase

"What I am saying is that there are both good uses and bad uses--just like
with every other language feature or intersection of features."

as

"We must avoid using macros where possible".






Ioannis Vranos
 
P

Paul Mensonides

Ioannis Vranos said:
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. You cannot define constants
that are usable to choose between various implementations each of which will
compile only on specific compilers on specific operating systems with underlying
language constants, but you can with macros. This list goes on and on.
So do you think macros should be used in every day's code?

"Every day code" is too general; it depends on what you are writing. If, for
example, you are writing a generic component (maybe some sort of "bind",
"compose", or "closure") you should, by all means, use the preprocessor to
generate code for you, such that you minimize the number of maintenance points
and increase the scalability of the component. OTOH, using macro definitions
instead of typedefs or using macro definitions instead of constant variables,
*is* pure evil most (but not all) of the time. Otherwise, macros can be used
locally (i.e. defined, used, undefined) for simple syntactic convenience. So,
to answer the question is, "Macros should be used when the use of macros is
better, and macros should not be used when the use of macros is not better."
Notice that the above doesn't present any black-and-white solution--it means you
have to *know* in any specific situation whether the use of macros is good,
evil, or the lesser of two evils.
I never said that "macros are evil". But (obviously) in the contrary of you,
i consider a good practice to try avoid using macros as much as it is
possible.

You said that one should avoid using macros because macros are "inherently
dangerous."
That statement is incorrect. How about using some guidelines that have a
modicum of validity? Like:

1) use all uppercase names only for macros
2) macros defined in headers (that are intended to propogate out of those
headers) should always be prefixed with some project/library prefix (i.e. a name
space)
3) macros defined in headers for local use only need not be prefixed, but should
specifically *not* be all uppercase and should *always* be undefined after use
(i.e. to prevent the possibility of a clash with an actual "external" macro
name).

Even with these guidelines there are some exceptions. The point, in any case,
is that the avoidance of macros in general is not a good guideline. Rather,
avoidance of certain usages of macros are good guidelines, and so on.
Otherwise, you are just tying your hands behind your back.
And also i never said the above. What i said is

"We must try to avoid using macros completely (mainly by using templates),
with very few exceptions that this can't be done (mainly the #ifndef
stuff)."

And that is simply false; it should be, "We must try to avoid using macros for
these kinds of purposes ... unless there is an exceptional reason to use them,"
and also, "If macros are to be used, they should be used according to these
guidelines ... unless there is an exceptional reason not to." Anything else is
presumptious and leads to brain-dead coding.
Well i agree. But i like to term the meaning of your phrase

Obviously you don't, because you obviously have no idea how macros are used in
modern libraries such as Boost. If you did, you would effectively be saying
that Boost is poorly implemented. If you are saying that, fine, but you have an
awfully high opinion of yourself to say such a thing. If you aren't saying
that, then you are naive regarding many of the issues involved in day to day
generic programming.
"What I am saying is that there are both good uses and bad uses--just like
with every other language feature or intersection of features."

as

"We must avoid using macros where possible".

The two are quite different, and the bad uses of macros do not outweight their
good uses enought (if they do at all) to draw an equivalence between the two
statements. According to your logic, you should also be saying, "We must avoid
using templates where possible." I.e. just because something *can* be used
poorly, doesn't mean that something cannot be used well, and, similarly, just
because something *can* be used well, doesn't mean that something cannot be used
poorly. In the case of templates, finding template-related bugs can be far far
worse than anything related to macros at all. Moral of the story, you cannot
condense good programming to a set of near black-and-white guidelines.

Regards,
Paul Mensonides
 
D

David Harmon

On Sat, 17 Apr 2004 21:07:07 -0700 in comp.lang.c++, "Paul Mensonides"
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.
 
I

Ioannis Vranos

Paul Mensonides said:
The two are quite different, and the bad uses of macros do not outweight their
good uses enought (if they do at all) to draw an equivalence between the two
statements. According to your logic, you should also be saying, "We must avoid
using templates where possible." I.e. just because something *can* be used
poorly, doesn't mean that something cannot be used well, and, similarly, just
because something *can* be used well, doesn't mean that something cannot be used
poorly. In the case of templates, finding template-related bugs can be far far
worse than anything related to macros at all. Moral of the story, you cannot
condense good programming to a set of near black-and-white guidelines.



I think it is a matter of views. I did not say to remove macros from the
language but i do not consider the macros matter as a balanced issue - that
there are as many good uses as bad uses. Macros are not to be used in daily
application programming.

For example i program C++ applications for .NET and i see no need to use
macros. On the other hand you seem to work in libraries area and you use
macros daily to get the job done. So perhaps the "default" for each one of
us is different. I can understand the use of macros in libraries, but still
even in that case my "default" would not be to use macros but only where i
can't do work without them.

There are things one can do only with macros, and i would use macros only to
do those.


Some quotes from TC++PL 3:


Page 10:

"The template facility was primarily designed to support statically typed
containers (such as lists, vectors, and maps) and to support elegant and
efficient use of such containers (generic programming). A key aim was to
reduce the use of macros and casts (explicit type conversion)."


Page 14:

"1.6.1 Suggestions for C Programmers

The better one knows C, the harder it seems to be to avoid writing C++ in C
style, thereby losing some of the potential benefits of C++. Please take a
look at Appendix B, which describes the differences between C and C++. Here
are a few pointers to the areas in which C++ has better ways of doing
something than C has:

[1] Macros are almost never necessary in C++. Use const (§5.4) or enum
(§4.8) to define manifest constants, inline (§7.1.1) to avoid function
calling overhead, templates (Chapter 13) to specify families of functions
and types, and namespaces (§8.2) to avoid name clashes."



Page 160:

"7.8 Macros

Macros are very important in C but have far fewer uses in C++. The first
rule about macros is: Don't use them unless you have to. Almost every macro
demonstrates a flaw in the programming language, in the program, or in the
programmer. Because they rearrange the program text before the compiler
proper sees it, macros are also a major problem for many programming tools.
So when you use macros, you should expect inferior service from tools such
as debuggers, crossreference tools, and profilers. If you must use macros,
please read the reference manual for your own implementation of the C++
preprocessor carefully and try not to be too clever. Also to warn readers,
follow the convention to name macros using lots of capital letters."


Page 161:

"Using macros, you can design your own private language. Even if you prefer
this ''enhanced language'' to plain C++, it will be incomprehensible to most
C++ programmers. Furthermore, the C preprocessor is a very simple macro
processor. When you try to do something non-trivial, you are likely to find
it either impossible or unnecessarily hard to do. The const, inline,
template, and namespace mechanisms are intended as alternatives to many
traditional uses of preprocessor constructs.

For example:

const int answer = 42;
template<class T> inline T min(T a, T b) { return (a<b)?a:b; }"





Page 163:

"7.9 Advice

[1] Be suspicious of non-const reference arguments; if you want the function
to modify its arguments, use pointers and value return instead; §5.5.
[2] Use const reference arguments when you need to minimize copying of
arguments; §5.5.
[3] Use const extensively and consistently; §7.2.
[4] Avoid macros; §7.8."







Ioannis Vranos
 
P

Paul Mensonides

David Harmon said:
On Sat, 17 Apr 2004 21:07:07 -0700 in comp.lang.c++, "Paul Mensonides"


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
 
I

Ioannis Vranos

Paul Mensonides said:
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.



Macros must be avoided where possible. In an effort to not hurt your
feelings we can rephrase that "Use macros only when needed". Choose whatever
fits you better, they are both the same. And C++ is not C, you may have been
a C programmer for some long time and have done a lot of real and excellent
work with macros, but C++ is not C and in most cases the language provides
superior alternatives.

On the other hand, if you *still* program in C and you use macros, then what
we discuss here does not apply.

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


Namespaces do not exist to protect from name collisions. Namespaces are the
implementation of the modular programming paradigm, that is to place the
data and its functions in an area (you can call it as the ancestor of OO
but it is a non-obsolete useful paradim), so as to have them together. E.g.:


namespace whatever
{
int x;

void somefunc(const int a) { /* Do things with x; */ }
int someotherfunc(int a) { /* Do some other things with x */ }
// ...
}



That's the modular paradigm namespaces was made for. Today we use this
paradigm with classes, etc too. And they help use different implementations
of the same facilities, e.g. std::vector vs
some_other_implementation::vector.

And something most do not know is that the use of a global namespace
declaration is not good. E.g.


#include <iostream>
#include <vector>

using namespace std;


int main()
{
// ..
}


is bad style. For accuracy it is an attempt to defeat the namespace system.
That's why a typical C++ standard library implementation of <stdio.h> is (or
better should be):


--- stdio.h ---

#include <cstdio>
using std::printf;
using std::sprintf;
// ...
using std::scanf;

// etc

--- end of C++ stdio.h ---


In summary, namespaces are not made to protect from name collisions among
functions doing different things, but to organize work and *protect* from
name collisions of facilities doing the same things.






Regards,

Ioannis Vranos
 
I

Ioannis Vranos

Ioannis Vranos said:
And something most do not know is that the use of a global namespace
declaration is not good. E.g.


#include <iostream>
#include <vector>

using namespace std;


int main()
{
// ..
}


is bad style. For accuracy it is an attempt to defeat the namespace system.
That's why a typical C++ standard library implementation of <stdio.h> is (or
better should be):


--- stdio.h ---

#include <cstdio>
using std::printf;
using std::sprintf;
// ...
using std::scanf;

// etc

--- end of C++ stdio.h ---


Now it is an entirely new topic, but since i got in, it is not good to leave
it unexplained. In a brief summary we must try using namespace declarations
in as a small scope as possible in the style:

For a couple of facilities, we must use "using namespace_name::facility;" in
as a small scope as possible. Example:


#include <iostream>

int main()
{
using std::cout;
using std::endl;

// ...

cout<</* ... */<<endl;

// ...

cout<</* ... */<<endl;
}


For more than a couple of things, we must use "using namespace
namespace_name;" in as a small scoe as possible. Example:


#include <iostream>
#include <vector>

int main()
{
using namespace std;

vector<int>whatever(10);

// ...

for(vector<int>::size_type i=0; i<whatever.size(); ++i)
cout<<whatever<<endl;

// ...

for(vector<int>::size_type i=0; i<whatever.size(); ++i)
cout<<whatever<<endl;
}






Ioannis Vranos
 
D

David Harmon

On Sun, 18 Apr 2004 13:55:36 -0700 in comp.lang.c++, "Paul Mensonides"
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.

Lexical analyzer? Show me a C preprocessor implementation of anything
to compare with Joel de Guzman's Spirit parser template library.
http://spirit.sf.net
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top