Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

#ifdef depreciated?

4 views
Skip to first unread message

John Friesen

unread,
Sep 16, 2002, 7:20:42 AM9/16/02
to
In the documentation for Visual C++ 6.0 there is the following statement :
"You can use the #ifdef and #ifndef directives anywhere #if can be
used...These directives are provided only for compatibility with previous
versions of the language. The defined( identifier ) constant expression used
with the #if directive is preferred."

However, I cannot find the #if defined(identifier) directive mentioned
anywhere in The C++ Programming Language Special Edition.

Is there an intention to depreciate the #ifdef and #ifndef directives?

Thank you,
John Friesen


[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]

Francis Glassborow

unread,
Sep 17, 2002, 6:10:19 AM9/17/02
to
In article <L_5h9.321696$v53.16...@news3.calgary.shaw.ca>, John
Friesen <frie...@shaw.ca> writes

>In the documentation for Visual C++ 6.0 there is the following statement :
>"You can use the #ifdef and #ifndef directives anywhere #if can be
>used...These directives are provided only for compatibility with previous
>versions of the language. The defined( identifier ) constant expression used
>with the #if directive is preferred."
>
>However, I cannot find the #if defined(identifier) directive mentioned
>anywhere in The C++ Programming Language Special Edition.
>
>Is there an intention to depreciate the #ifdef and #ifndef directives?

There is a curious hole in good books about C++ that you have just
highlighted. The C++ Primer (Lippman and Lajoie) does not even mention
#if as far as I can ascertain (it certainly isn't in the index) but does
cover #ifdef and #ifndef.

The C++ Standard does cover the issue in para 1 of 16.1 but the grammar
only sort of manages to cover it dependent on your awareness that there
is a pre-processing unary operator 'defined' which is only defined in
this paragraph. That definition implicitly makes 'defined identifier'
and 'defined (identifier)' constant expressions.

16.1 para 5 defines #ifdef and #ifndef in terms of #if with defined and
!defined respectively.

--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

Erik Max Francis

unread,
Sep 17, 2002, 7:01:45 AM9/17/02
to
John Friesen wrote:

> In the documentation for Visual C++ 6.0 there is the following
> statement :
> "You can use the #ifdef and #ifndef directives anywhere #if can be
> used...These directives are provided only for compatibility with
> previous
> versions of the language. The defined( identifier ) constant
> expression used
> with the #if directive is preferred."
>
> However, I cannot find the #if defined(identifier) directive mentioned
> anywhere in The C++ Programming Language Special Edition.
>
> Is there an intention to depreciate the #ifdef and #ifndef directives?

No, #ifdef is not deprecated. It looks like VC++ is trying to dictate a
particular style.

Some people like #ifdef ..., some people prefer #if defined(...). The
only situation in which one is clearly advantageous is if you need to
check multiple defines:

#if defined(UNIX) && !defined(SYSV)
...

--
Erik Max Francis / m...@alcyone.com / http://www.alcyone.com/max/
__ San Jose, CA, US / 37 20 N 121 53 W / ICQ16063900 / &tSftDotIotE
/ \ Life imitates art far more than art imitates life.
\__/ Oscar Wilde
7 Sisters Productions / http://www.7sisters.com/
Web design for the future.

Jack Klein

unread,
Sep 17, 2002, 4:49:06 PM9/17/02
to
On 16 Sep 2002 07:20:42 -0400, John Friesen <frie...@shaw.ca> wrote
in comp.lang.c++.moderated:

> In the documentation for Visual C++ 6.0 there is the following
statement :
> "You can use the #ifdef and #ifndef directives anywhere #if can be
> used...These directives are provided only for compatibility with
previous
> versions of the language. The defined( identifier ) constant
expression used
> with the #if directive is preferred."
>
> However, I cannot find the #if defined(identifier) directive mentioned
> anywhere in The C++ Programming Language Special Edition.
>
> Is there an intention to depreciate the #ifdef and #ifndef directives?
>
> Thank you,
> John Friesen

I have no idea where they got that idea, certainly not from the C++
standard. It contains all of the C preprocessor directives, including
#if, #ifdef, and #ifndef, and none of them are marked as deprecated.

Nor are any of them deprecated in the current version of the C
standard, which is a year newer than the C++ standard.

It is extremely unlikely that these would ever go away, as that would
break huge quantities of existing code for no gain whatsoever.

Microsoft's own headers supplied with Visual C++ 6.0 all use include
guards that look like this:

#ifndef _UPPERCASE_IDENTIFIER
#define _UPPERCASE_IDENTIFIER
// actual header contents
#endif

So they'd break their own headers, not that they haven't done this
before.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq

apm

unread,
Sep 17, 2002, 5:01:50 PM9/17/02
to
John Friesen <frie...@shaw.ca> wrote in message
news:<L_5h9.321696$v53.16...@news3.calgary.shaw.ca>...

> In the documentation for Visual C++ 6.0 there is the following
statement :
> "You can use the #ifdef and #ifndef directives anywhere #if can be
> used...These directives are provided only for compatibility with
previous
> versions of the language. The defined( identifier ) constant
expression used
> with the #if directive is preferred."
>
> However, I cannot find the #if defined(identifier) directive mentioned
> anywhere in The C++ Programming Language Special Edition.
>
> Is there an intention to depreciate the #ifdef and #ifndef directives?

Section 16.1, paragraph 5 of the ISO standard points out that the
directives conditions "are equivalent to #if defined identifer and #if
!defined identifier respectively". So the standard points out that the
construct is redundant but does not call it deprecated.

-Andrew M.

Francis Glassborow

unread,
Sep 17, 2002, 5:04:01 PM9/17/02
to
In article <3D8625D1...@alcyone.com>, Erik Max Francis
<m...@alcyone.com> writes

>Some people like #ifdef ..., some people prefer #if defined(...).

Yep. But nonetheless the C++ Standard defines #ifdef in terms of #if
defined. IOWs the older form has been subsumed into a newer broader one.

I suspect that had we not already had the older form, it would not be
provided as a shortcut for special cases of the broader one.

I think VC++ is actually doing us all a favour by reminding us that we
have a more general syntax available.

--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Michael Spencer

unread,
Sep 18, 2002, 6:16:44 PM9/18/02
to
John Friesen wrote:
> In the documentation for Visual C++ 6.0 there is the following
statement :
> "You can use the #ifdef and #ifndef directives anywhere #if can be
> used...These directives are provided only for compatibility with
previous
> versions of the language. The defined( identifier ) constant
expression used
> with the #if directive is preferred."
>
> However, I cannot find the #if defined(identifier) directive
mentioned
> anywhere in The C++ Programming Language Special Edition.
>
> Is there an intention to depreciate the #ifdef and #ifndef
directives?
>
> Thank you,
> John Friesen
>

Note that some tools optimize reading files enclosed in '#ifndef'
conditionals. From the CPP info page:

The GNU C preprocessor is programmed to notice when a header file
uses this particular construct and handle it efficiently. If a header
file is contained entirely in a `#ifndef' conditional, then it records
that fact. If a subsequent `#include' specifies the same file, and the
macro in the `#ifndef' is already defined, then the file is entirely
skipped, without even reading it.

Mike
--
Be lazy: http://www.lazycplusplus.com

Rob

unread,
Sep 21, 2002, 9:15:19 AM9/21/02
to
"Francis Glassborow" <francis.g...@ntlworld.com> wrote in message
news:EU80RJGV...@robinton.demon.co.uk...

> In article <3D8625D1...@alcyone.com>, Erik Max Francis
> <m...@alcyone.com> writes
> >Some people like #ifdef ..., some people prefer #if defined(...).
>
> Yep. But nonetheless the C++ Standard defines #ifdef in terms of #if
> defined. IOWs the older form has been subsumed into a newer broader one.
>
> I suspect that had we not already had the older form, it would not be
> provided as a shortcut for special cases of the broader one.

That may be true, but is not the same as saying that #ifdef and #ifndef
are deprecated (or depreciated). Heck, if being defined in terms of
other part(s) of the language was enough to render something depreciated,
the bulk of many programming languages would formally be depreciated.

>
> I think VC++ is actually doing us all a favour by reminding us that we
> have a more general syntax available.
>

Maybe, but from what I recall of the wording that was quoted in
the first message of this thread, I received the impression they
were doing a bit more than a gentle reminder; they were giving
a false impression that #ifdef and #ifndef are likely to go away.

Alan Balmer

unread,
Sep 22, 2002, 10:15:40 AM9/22/02
to
On 16 Sep 2002 07:20:42 -0400, John Friesen <frie...@shaw.ca> wrote:

>"You can use the #ifdef and #ifndef directives anywhere #if can be
>used...These directives are provided only for compatibility with previous
>versions of the language. The defined( identifier ) constant expression used
>with the #if directive is preferred."

This is not a statement about the standard, it's a statement about Microsoft
philosophy. Microsoft is a standard unto themselves.

If MS decided not to support #ifdef, millions of programmers would curse and
change their code.


Al Balmer
Balmer Consulting

John Torjo

unread,
Sep 23, 2002, 2:48:30 PM9/23/02
to
John Friesen <frie...@shaw.ca> wrote in message
news:<L_5h9.321696$v53.16...@news3.calgary.shaw.ca>...
> In the documentation for Visual C++ 6.0 there is the following
statement :
> "You can use the #ifdef and #ifndef directives anywhere #if can be
> used...These directives are provided only for compatibility with
previous
> versions of the language. The defined( identifier ) constant
expression used
> with the #if directive is preferred."
>
> However, I cannot find the #if defined(identifier) directive mentioned
> anywhere in The C++ Programming Language Special Edition.
>
> Is there an intention to depreciate the #ifdef and #ifndef directives?

No way ;-)

#ifdef & #ifndef are shortcuts.
However, I (and think many others) prefer #if defined(directive),
since it's more maintainable.

For example, if I have something like:
#if defined(__GNUC__)
...
#endif

and in the future I want to ask if we're using GCC or VC, I will
append code to the first line, like this:
#if defined(__GNUC__) || defined(_MSC_VER)
...

Had the first line been '#ifdef __GNUC__', I would have had to change
the whole line...

Best,
John

--
John Torjo
C++ tips techmail writer for builder.com.com

Applications Development Manager
People First Software

mailto:john....@peoplefirstsoft.com
www.peoplefirstsoft.com

Andreas Gieriet

unread,
Sep 24, 2002, 7:00:12 AM9/24/02
to
What about the header file guard idiom?

I think this is always written as:

#ifndef XXX
#define XXX
...<header file data>...
#endif

I've never seen something like:

#if !defined(XXX)
#define XXX
...
#endif


Cheers

Andi

--
Andreas Gieriet mailto:andreas...@externsoft.ch
eXternSoft GmbH http://www.externsoft.com/
Zurlindenstrasse 49 phone:++41 1 454 3077
CH-8003 Zurich/SWITZERLAND fax: ++41 1 454 3078

André Pönitz

unread,
Sep 24, 2002, 5:35:36 PM9/24/02
to
Andreas Gieriet <andreas...@externsoft.ch> wrote:
> What about the header file guard idiom?
>
> I think this is always written as:
>
> #ifndef XXX
> #define XXX
>
> [...]

> I've never seen something like:
>
> #if !defined(XXX)
> #define XXX

I've actually seen both for header guards. Look like a matter of style again.

I personally prefer the first one, mainly for aesthetical reason. [Well,
one could argue that mistypings are easier spotted this way...]

Andre'

--
Those who desire to give up Freedom in order to gain Security,
will not have, nor do they deserve, either one. (T. Jefferson)

Francis Glassborow

unread,
Sep 24, 2002, 5:41:15 PM9/24/02
to
In article <3D8FF594...@externsoft.ch>, Andreas Gieriet
<andreas...@externsoft.ch> writes

>What about the header file guard idiom?
>
>I think this is always written as:
>
>#ifndef XXX
>#define XXX
>...<header file data>...
>#endif
>
>I've never seen something like:
>
>#if !defined(XXX)
>#define XXX
>...
>#endif

Of course that does not make it wrong. Actually, one of the benefits
from the warning message that started this thread is that it draws
attention to the latter syntax, which a surprising number of C & C++
programmers are unaware of.


--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Daniel James

unread,
Sep 24, 2002, 6:04:51 PM9/24/02
to
In article <3D8625D1...@alcyone.com>, Erik Max Francis wrote:
> Some people like #ifdef ..., some people prefer #if defined(...).
> The only situation in which one is clearly advantageous is if you
> need to check multiple defines:
>
> #if defined(UNIX) && !defined(SYSV)
> ...

True. And as there's no #elifdef it looks pretty strange to mix
styles in:

#ifdef WINDOWS
... stuff
#elif defined(UNIX)
... other stuff
#else
...

Cheers,
Daniel.

John Torjo

unread,
Sep 24, 2002, 6:17:15 PM9/24/02
to
Andreas Gieriet <andreas...@externsoft.ch> wrote in message news:<3D8FF594...@externsoft.ch>...

> What about the header file guard idiom?
>
> I think this is always written as:
>
> #ifndef XXX
> #define XXX
> ...<header file data>...
> #endif
>
> I've never seen something like:
>
> #if !defined(XXX)
> #define XXX
> ...
> #endif
>

You're quite right about that.
I forgot about this, since most of the time, the wizard does that for me ;-)

Best,
John

--
John Torjo
C++ tips techmail writer for builder.com.com

Applications Development Manager
People First Software

mailto:john....@peoplefirstsoft.com
www.peoplefirstsoft.com

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

unread,
Sep 24, 2002, 7:30:06 PM9/24/02
to
jto...@yahoo.com (John Torjo) wrote in message
news:<c638aac5.02092...@posting.google.com>...

> John Friesen <frie...@shaw.ca> wrote in message
> news:<L_5h9.321696$v53.16...@news3.calgary.shaw.ca>...

> > In the documentation for Visual C++ 6.0 there is the following
> > statement :
> > "You can use the #ifdef and #ifndef directives anywhere #if can be
> > used...These directives are provided only for compatibility with
> > previous versions of the language. The defined( identifier )
> > constant expression used with the #if directive is preferred."

> > However, I cannot find the #if defined(identifier) directive
> > mentioned anywhere in The C++ Programming Language Special Edition.

> > Is there an intention to depreciate the #ifdef and #ifndef
directives?

> No way ;-)

> #ifdef & #ifndef are shortcuts.
> However, I (and think many others) prefer #if defined(directive),
> since it's more maintainable.

It depends on the context.

For include guards, I use #ifndef. Include guards are a special case,
and worthy of their own idiom.

In production code, all other use of #if is forbidden. No point in
making life difficult for the guy who comes after me.

If you really must use a #if, then it should be for some symbolic name.
Not
#if defined(__GNUC__) and __GNUC__ <= 2
but
#ifndefm NONEWISTREAM

> For example, if I have something like:
> #if defined(__GNUC__)
> ...
> #endif

If you have something like that, you have violated every coding
guideline I have ever seen.

> and in the future I want to ask if we're using GCC or VC, I will
> append code to the first line, like this:
> #if defined(__GNUC__) || defined(_MSC_VER)
> ...

Why not a symbolic name for what you are testing? A symbolic name
defined in a single, system dependant include?

Or better, write your code so that it doesn't need the test. (I've used
such tests in experimental code, but never in production code.)

> Had the first line been '#ifdef __GNUC__', I would have had to change
> the whole line...

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

John Levon

unread,
Sep 25, 2002, 6:08:11 PM9/25/02
to
James Kanze wrote:

> It depends on the context.
>
> For include guards, I use #ifndef. Include guards are a special case,
> and worthy of their own idiom.

And as somebody has already alluded to, it's actually safer :

#if !defined(NECASSARY_H)
#define NECESSARY_H

#ifndef NECASSARY_H
#define NECESSARY_H

It's far easier to spot the mistake in the second form. And on
occassions, this sort of silly typo can take some real effort to find
when you end up with some odd compile problem.

Of course, in most circumstances, it's best to use some automated way of
adding the include guards anyway.

> Or better, write your code so that it doesn't need the test. (I've used
> such tests in experimental code, but never in production code.)

I'm intrigued how you cope with typical compiler standard infelicities
without the (hopefully very occassional) compiler-specific ifdef.

regards
john


--
Tedious line noise since 1977.

Gennaro Prota

unread,
Sep 25, 2002, 6:09:45 PM9/25/02
to
On 24 Sep 2002 19:30:06 -0400, ka...@gabi-soft.de (James Kanze) wrote:

>Why not a symbolic name for what you are testing? A symbolic name
>defined in a single, system dependant include?
>
>Or better, write your code so that it doesn't need the test. (I've used
>such tests in experimental code, but never in production code.)

Of course I completely agree about the 'test for features, not for
systems'. However, to be sure that I understand you: do you *always*
avoid conditional compilation by using different source files in
different directories and setting the appropriate search paths? If so,
I would say horses for courses; that's certainly a good solution when,
for instance, you have two completely different implementations but it
would be a maintenance nightmare in case e.g. you had a function where
just one or two lines need some workaround (#if HAS_xyz_BUG et
similia).

Genny.

James Kanze

unread,
Sep 26, 2002, 1:11:21 PM9/26/02
to
Gennaro Prota <gennar...@yahoo.com> wrote in message
news:<dsi3puku3h5602l33...@4ax.com>...

> On 24 Sep 2002 19:30:06 -0400, ka...@gabi-soft.de (James Kanze) wrote:

> >Why not a symbolic name for what you are testing? A symbolic name
> >defined in a single, system dependant include?

> >Or better, write your code so that it doesn't need the test. (I've
> >used such tests in experimental code, but never in production code.)

> Of course I completely agree about the 'test for features, not for
> systems'. However, to be sure that I understand you: do you *always*
> avoid conditional compilation by using different source files in
> different directories and setting the appropriate search paths? If so,
> I would say horses for courses; that's certainly a good solution when,
> for instance, you have two completely different implementations but it
> would be a maintenance nightmare in case e.g. you had a function where
> just one or two lines need some workaround (#if HAS_xyz_BUG et
> similia).

I don't think I've ever used an #ifdef in production code. There are
two types of differences between systems:

- One system supports features that the other system lacks. If you
need to target both systems, you don't use these features. It's as
simple as that.

- Both systems support the same functionnality, but in different
ways. The obvious examples are sockets or threads. And the obvious
solution is to encapsulate the functionality in an object, or if it
is really, really small, in macros. (I used macros for a while to
use the new style casts where they were supported, the old style
otherwise.)

Can you show me an example of something else? Where you might actually
want to use an #ifdef in the code. I've never yet encountered a case
where I would want to, although I think I would resist if I did; I can't
think of anything which would make the code harder to maintain.

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

unread,
Sep 26, 2002, 4:29:20 PM9/26/02
to
John Levon <le...@movementarian.org> wrote in message
news:<amse0i$ci3$1...@news8.svr.pol.co.uk>...
> James Kanze wrote:

> > Or better, write your code so that it doesn't need the test. (I've
> > used such tests in experimental code, but never in production code.)

> I'm intrigued how you cope with typical compiler standard infelicities
> without the (hopefully very occassional) compiler-specific ifdef.

I write to the common subset. The variations are generally that some
compiler is missing a certain feature. In that case, I have to develop
code without that feature anyway. Since the code without the feature
works even with compilers with the feature, I just use it everywhere.
There's no point in maintaining two versions, just to be fancy.

Can you give me an example of where a #if might make sense?

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Gerhard Menzl

unread,
Sep 27, 2002, 6:35:52 AM9/27/02
to
James Kanze wrote:

> I don't think I've ever used an #ifdef in production code. There are
> two types of differences between systems:
>
> - One system supports features that the other system lacks. If you
> need to target both systems, you don't use these features. It's
> as simple as that.
>
> - Both systems support the same functionnality, but in different
> ways. The obvious examples are sockets or threads. And the
> obvious solution is to encapsulate the functionality in an
> object, or if it is really, really small, in macros. (I used
> macros for a while to use the new style casts where they were
> supported, the old style otherwise.)
>
> Can you show me an example of something else? Where you might
> actually want to use an #ifdef in the code. I've never yet
> encountered a case where I would want to, although I think I would
> resist if I did; I can't think of anything which would make the code
> harder to maintain.

In principle, I agree. #ifdef can be used very efficiently to obfuscate
source code beyond redemption. I've seen eight thousand line functions
sprinkled with nested #ifdefs that were used to tweak the code for
individual customers. You definitely don't want to go down that path.

On the other hand, I don't think it is necessary to get fundamentalist
about it. For example, how would you solve the following problem?

14.1/12 prohibits the repeated specification of default template
arguments in different declarations:

template <class Traits = DefaultTraits> X;

template <class Traits = DefaultTraits> X { /* ... */ }; // error

I have one compiler that complies with this rule and one compiler that
requires its violation. My code is required to compile with both
implementations. Do you really think putting the offending forward
delcaration in a file of its own and maintaining two versions is going
to ease maintenance? Should I remove the forward declaration and
increase coupling, or should I forgo the use of default template
arguments altogether, just for the sake of obeying an iron rule?

My STL implementation bristles with workarounds of that sort. It is
certainly a good idea to decouple the source code from the preprocessor
symbol that identifies the compiler and version by testing for
meaningful identifiers and keeping the compiler-specific dependencies in
a central place, i.e.

#ifdef DEFAULT_TEMPLATE_ARGUMENT_RESPECIFICATION_BUG

rather than

#if defined(__EASYCPLUSPLUS__) && (__EASYCPLUSPLUSVERSION__ <= 3)

But banning such workarounds altogether is not going to help anyone and
will make writing portable libraries that are not restricted to the most
primitive language features impossible.

Of course, if you could recommend a better technique, I would be happy
to adopt it.

Gerhard Menzl
--
#dogma int main()

Jean-Marc Bourguet

unread,
Sep 27, 2002, 1:44:27 PM9/27/02
to
Gerhard Menzl <gerhar...@sea.ericsson.se> writes:

> For example, how would you solve the following problem?
>
> 14.1/12 prohibits the repeated specification of default template
> arguments in different declarations:
>
> template <class Traits = DefaultTraits> X;
>
> template <class Traits = DefaultTraits> X { /* ... */ }; // error
>
> I have one compiler that complies with this rule and one compiler that
> requires its violation. My code is required to compile with both
> implementations.

In a header workaroud.h declare a macro

REPEATED_DEFAULT_TEMPLATE_ARGUMENTS

then and use

template <class Traits REPEATED_DEFAULT_TEMPLATE_ARGUMENTS(= DefaultTraits) > X...

Personnaly I don't really care if workaroud.h is full of #ifdef or if
there are as many versions as system/compilers pairs as needed.
That'd probably depend on the build environment and other things.

--
Jean-Marc

David Cattarin

unread,
Sep 28, 2002, 6:28:52 AM9/28/02
to
ka...@gabi-soft.de (James Kanze) wrote in message news:<d6651fb6.02092...@posting.google.com>...
[snip]

> I don't think I've ever used an #ifdef in production code. There are
> two types of differences between systems:
>
> - One system supports features that the other system lacks. If you
> need to target both systems, you don't use these features. It's as
> simple as that.

No, it's not. That's the problem with generalizations. What happens
when you *have* to have the feature due to requirements? Then, on the
offending platforms, you have to simulate it. You may encapulate the
problem in a file/class/function, but at some point, you might very
well have to use #ifdef to choose between the provided feature and the
simulated one.

> - Both systems support the same functionnality, but in different
> ways. The obvious examples are sockets or threads. And the obvious
> solution is to encapsulate the functionality in an object, or if it
> is really, really small, in macros. (I used macros for a while to
> use the new style casts where they were supported, the old style
> otherwise.)

This isn't really true either. Case in point: compiler bugs. I
recently found a bizarre problem with certain HP compilers. The
compiler would fail to compile valid switch code. It claimed that the
break was incorrect. The only way to work around this was to #ifdef
the break and replace it with a goto for the "offending" lines.

> Can you show me an example of something else? Where you might actually
> want to use an #ifdef in the code. I've never yet encountered a case
> where I would want to, although I think I would resist if I did; I can't
> think of anything which would make the code harder to maintain.

How about #pragmas. You might want to #ifdef these to avoid confusing
a compiler on a different platform. For people doing windows'
programming, I'm sure the following construct is familiar:

#ifdef WIN32
# pragma warning ( disable : 4786 ) // warning for truncated
debugging info
#endif

This avoids disabling the wrong warning for a different compiler.

How about compilers with different levels of standards compliance. I
use the following code to get around problems with ostream formatting.

#ifndef NO_IOS_BASE
# ifndef NO_STD_NAMESPACE
using std::ios_base;
# endif
typedef ios_base::fmtflags FmtFlags;
static const FmtFlags gPropFormat = ios_base::right;
#else
# ifndef NO_STD_NAMESPACE
using std::ios;
# endif
# ifdef USE_OLD_IOSTREAM
typedef int FmtFlags;
# else
typedef ios::fmtflags FmtFlags;
# endif
static const FmtFlags gPropFormat = ios::right;
#endif

I feel that #ifdef (and #if) have valid places in production code.

Dave

Gennaro Prota

unread,
Sep 28, 2002, 1:09:09 PM9/28/02
to
On 27 Sep 2002 06:35:52 -0400, Gerhard Menzl
<gerhar...@sea.ericsson.se> wrote:

> For example, how would you solve the following problem?
>
>14.1/12 prohibits the repeated specification of default template
>arguments in different declarations:
>
> template <class Traits = DefaultTraits> X;
>
> template <class Traits = DefaultTraits> X { /* ... */ }; // error
>
>I have one compiler that complies with this rule and one compiler that
>requires its violation. My code is required to compile with both
>implementations. Do you really think putting the offending forward
>delcaration in a file of its own and maintaining two versions is going
>to ease maintenance?

If you want to have the default arguments _and_ the forward
declaration, that's not even a solution because the problem concerns
the definition. This situation arose with boost::dynamic_bitset (see
the files in the CVS). I suppose in such a case Mr. Kanze would simply
include the header with the definition and give up using forward
declarations. But that's a bad service to people who have serious
compilers: they have to pay for a defect of someone else.

Genny.

Gabriel Dos Reis

unread,
Sep 30, 2002, 9:46:14 AM9/30/02
to
ka...@gabi-soft.de (James Kanze) writes:

| - One system supports features that the other system lacks. If you
| need to target both systems, you don't use these features. It's
as
| simple as that.

As a corollary, a C++ implementation targetting different plateforms
should not support (and use) multithreading facilities on system X
(that does offer them) just because system Y doesn't have them. <g>

--
Gabriel Dos Reis g...@integrable-solutions.net

Gabriel Dos Reis

unread,
Sep 30, 2002, 9:46:38 AM9/30/02
to
Gennaro Prota <gennar...@yahoo.com> writes:

[...]

| I suppose in such a case Mr. Kanze would simply
| include the header with the definition and give up using forward
| declarations. But that's a bad service to people who have serious
| compilers: they have to pay for a defect of someone else.

Maybe in such case, Mr. Kanze won't support more than one C++
implementation ;-)

--
Gabriel Dos Reis g...@integrable-solutions.net

Gerhard Menzl

unread,
Sep 30, 2002, 5:30:34 PM9/30/02
to
Jean-Marc Bourguet wrote:

> In a header workaroud.h declare a macro
>
> REPEATED_DEFAULT_TEMPLATE_ARGUMENTS
>
> then and use
>
> template <class Traits REPEATED_DEFAULT_TEMPLATE_ARGUMENTS(= > DefaultTraits) > X...
>
> Personnaly I don't really care if workaroud.h is full of #ifdef or if
> there are as many versions as system/compilers pairs as needed.
> That'd probably depend on the build environment and other things.

Personally, I find this rather unreadable, especially considering that
it also uglifies and obscures the code for the conforming case. A
judiciously used #ifdef is a lot easier to understand and maintain.

Gerhard Menzl

Thomas Mang

unread,
Sep 30, 2002, 6:21:13 PM9/30/02
to
ka...@gabi-soft.de (James Kanze) wrote in message
>
> I don't think I've ever used an #ifdef in production code. There are
> two types of differences between systems:
>
> - One system supports features that the other system lacks. If you
> need to target both systems, you don't use these features. It's as
> simple as that.

What do you do when one feature is implemented by one of your
compilers, and the other isn't (although standard conforming)?

There are hundreds (even more likely, thousands) of those little
compiler bugs around.
I think the "write it in standard C++, so it is 100% portable" holds
only true if you make use of not more than, say, the "basic"
functionality of C++ (I can, certainly, not define what this is.
Probably the stuff treated in the first chapters of beginners books).
I would not dare to use templates, if 100% portability is an issue.

What, other than conditional compilation using #if and its associates,
is your solution for this problem ?
Don't misunderstand me, I hate this

#if defined xxxx_BUG

#else

#endif

too. If you have a good solution to avoid this, please tell us.


I think not using these features is inacceptable in many cases.
Taking out of code everything that doesn't compile on the one or other
system would leave me with the "basic" C++ mentioned above. And then I
wouldn't use C++ anymore.


best regards,

Thomas

James Kanze

unread,
Oct 1, 2002, 12:05:06 PM10/1/02
to
Gerhard Menzl <gerhar...@sea.ericsson.se> wrote in message
news:<3D941342...@sea.ericsson.se>...
> James Kanze wrote:

> > I don't think I've ever used an #ifdef in production code. There
are

Before going further, I should point out that there are two very
important words in my first sentence.

The first is "production". I use #ifdef's when I'm experimenting with
new features, for example.

The second is "I've". I've not seen all possible applications. In
particular, I find it easy to conceive that some library providers use
#ifdef, since some of their customers may only use one, very advanced
compiler, and they don't wish to limit them because other customers have
older compilers. My experience is purely in applications, and not
generalized libraries, however, so I cannot really comment on what the
best solution to this problem would be.

> > as simple as that.

The solution in application code is simple: don't use default template
arguments.

> My code is required to compile with both implementations. Do you
> really think putting the offending forward delcaration in a file of
> its own and maintaining two versions is going to ease maintenance?
> Should I remove the forward declaration and increase coupling, or
> should I forgo the use of default template arguments altogether, just
> for the sake of obeying an iron rule?

Forgo default template arguments altogether. IMHO, the answer here is
simple. New features are a potential source of problems. Don't use
them until you know they work everywhere.

I'll admit that this is one of the limit cases, however, since both
compilers offer the functionality, just in different forms (and the user
code doesn't see the difference). Still, I suspect that if you need to
support two different variants of a new feature, the need will arise to
support a compiler which doesn't support the feature at all, and you'll
have to do without anyway.

> My STL implementation bristles with workarounds of that sort.

An STL implementation is what I would call a general library. As I said
above, I'm less certain about this, because I have no real experience
with it. At the very least, I, as a user, would hate to be deprived of
the template member functions because some of the library users (but not
me) have to compile with a compiler which doesn't support member
templates.

I don't think this argument holds for application code. I recently
removed all of the template members from my RefCntPtr because it must
compile with Sun CC 4.2 here. I want it to remain maintainable, and
since I can't use the template members anyway (since the code which uses
the class must also compile with Sun CC 4.2)...

> It is certainly a good idea to decouple the source code from the
> preprocessor symbol that identifies the compiler and version by
> testing for meaningful identifiers and keeping the compiler-specific
> dependencies in a central place, i.e.

> #ifdef DEFAULT_TEMPLATE_ARGUMENT_RESPECIFICATION_BUG

> rather than

> #if defined(__EASYCPLUSPLUS__) && (__EASYCPLUSPLUSVERSION__ <= 3)

> But banning such workarounds altogether is not going to help anyone
> and will make writing portable libraries that are not restricted to
> the most primitive language features impossible.

> Of course, if you could recommend a better technique, I would be happy
> to adopt it.

As usual, there is no black and white, only different shades of gray.
From what you say, I think you would agree that #ifdef within a function
is a horror, to be avoided at all costs. Generally speaking I would
prefer to avoid the #ifdef everywhere. But I recognize that some are
worse than others.

Like all of the rules in the coding guidelines, this one is subject to
the meta-rule that it can be broken if you can justify the reasons for
breaking it. I still have my doubts concerning your case, but any real
judgement would depend on the context -- not just the particular
problem, but who uses the code (general library, or specific to one
application, etc.), who has to maintain it, what the long term evolution
would seem to be, etc. The fact that there may be justifiable
exceptions doesn't mean that it isn't a good rule.

And don't read more into what I say that what I have written. I said
that I've never used an #ifdef in production code. (Other than as an
include guide -- I forgot that obvious exception.) My intent wasn't to
suggest that it was never justified; just to say that it was infrequent
enough that I've never encountered the case.

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

unread,
Oct 1, 2002, 1:08:32 PM10/1/02
to
Gabriel Dos Reis <g...@soliton.integrable-solutions.net> wrote in message
news:<m3lm5k7...@soliton.integrable-solutions.net>...
> Gennaro Prota <gennar...@yahoo.com> writes:

> [...]

> | I suppose in such a case Mr. Kanze would simply include the header
> | with the definition and give up using forward declarations. But
> | that's a bad service to people who have serious compilers: they have
> | to pay for a defect of someone else.

> Maybe in such case, Mr. Kanze won't support more than one C++
> implementation ;-)

More likely, I'd say that default template arguments are a feature that
isn't ripe enough for production code, and not use them. Or adopt a
solution along the lines of what Jean-Marc suggested. Or even decide
that the situation justified an exception to the rule: I'm a pragmatic
person.

However, as I have pointed out, my original statement concerned my
actual experience. I have no experience in general purpose libraries,
which must be delivered to many different customers. So maybe my
decision would be different in such a case.

I don't quite understand that when I make a statement openly concerning
my own experience ("I don't think I've ever used an #ifdef in production
code."), people take it as an absolute rule. I think that #ifdef are
something to avoid if at all possible. But like all rules, that is
subject to the meta-rule that it can be violated if the circumstances
justify. In this case, all I said was that in my own experience, I've
never encountered a case where the circumstances justified it. As a
statement, it has some informational value, because I have a fair amount
of experience, in both commercial and industrial domaines. But it is
hardly an absolute, since there are other domains (general purpose
libraries, game software, numerics) in which I've no experience; since
even in the domains I have experience, there might be particular cases
that I have experienced; and since I rather nuanced the statement
anywhere "I don't think I've ever ...". My understanding of English is
that there is a significant difference between "I don't think I've
ever ..." and "No one must ever ...".

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

unread,
Oct 1, 2002, 1:09:15 PM10/1/02
to
dit...@ix.netcom.com (David Cattarin) wrote in message
news:<30869baf.02092...@posting.google.com>...

> ka...@gabi-soft.de (James Kanze) wrote in message
> news:<d6651fb6.02092...@posting.google.com>...
> [snip]
> > I don't think I've ever used an #ifdef in production code. There
are
> > two types of differences between systems:

> > - One system supports features that the other system lacks. If
you
> > need to target both systems, you don't use these features.
It's as
> > simple as that.

> No, it's not. That's the problem with generalizations. What happens
> when you *have* to have the feature due to requirements? Then, on the
> offending platforms, you have to simulate it. You may encapulate the
> problem in a file/class/function, but at some point, you might very
> well have to use #ifdef to choose between the provided feature and the
> simulated one.

Why not use the "simulated" solution everywhere? Why maintain two
solutions, when one would be enough?

And what are the requirements that are formulated at such implementation
detail levels?

> > - Both systems support the same functionnality, but in different
> > ways. The obvious examples are sockets or threads. And the
obvious
> > solution is to encapsulate the functionality in an object, or
if it
> > is really, really small, in macros. (I used macros for a while
to
> > use the new style casts where they were supported, the old
style
> > otherwise.)

> This isn't really true either. Case in point: compiler bugs. I
> recently found a bizarre problem with certain HP compilers. The
> compiler would fail to compile valid switch code. It claimed that the
> break was incorrect. The only way to work around this was to #ifdef
> the break and replace it with a goto for the "offending" lines.

Why do you need the #ifdef? Wouldn't the goto work with the other
compilers?

> > Can you show me an example of something else? Where you might
> > actually want to use an #ifdef in the code. I've never yet
> > encountered a case where I would want to, although I think I would
> > resist if I did; I can't think of anything which would make the
> > code harder to maintain.

> How about #pragmas.

You win:-). They must be worse than #ifdef's. (But I suppose it
depends on the #pragma. A pragma that turns certain warnings on or off
shouldn't cause any real problems. A pragma that changes the semantics
of legal code will render the program totally unmaintainable, however.)

> You might want to #ifdef these to avoid confusing a compiler on a
> different platform. For people doing windows' programming, I'm sure
> the following construct is familiar:

> #ifdef WIN32
> # pragma warning ( disable : 4786 ) // warning for truncated
> debugging info
> #endif

> This avoids disabling the wrong warning for a different compiler.

Well, it seems strange to me that such a silly warning would be on in
the first place (or even exist), but who knows. But surely want to
disable it globally, and the command line is the place for that. And if
only a pragm will do:

#include "SystemPragmas.hh"

with a version of the header for each system, in a system dependant
directory specified by a -I option in the command line.

Note that I'm not really trying to be dogmatic here, but to indicate
that other solutions exist, and that except in rare cases, they will be
preferable.

> How about compilers with different levels of standards compliance. I
> use the following code to get around problems with ostream formatting.

> #ifndef NO_IOS_BASE
> # ifndef NO_STD_NAMESPACE
> using std::ios_base;
> # endif
> typedef ios_base::fmtflags FmtFlags;
> static const FmtFlags gPropFormat = ios_base::right;
> #else
> # ifndef NO_STD_NAMESPACE
> using std::ios;
> # endif
> # ifdef USE_OLD_IOSTREAM
> typedef int FmtFlags;
> # else
> typedef ios::fmtflags FmtFlags;
> # endif
> static const FmtFlags gPropFormat = ios::right;
> #endif

At present, my application level code only includes my own IO headers:
"iostream.hh", "istream.hh", etc. Again, these files exist in different
versions, in different directories, and the version used is selected by
a -I option in the command line. The file "ios.hh" is either:

#include <ios>
namespace Gabi {
typedef GB_iostd::ios_base::fmtflags FmtFlags ;
static int const eof = GB_iostd::char_traits<char>::eof() ;
}

or:

#include <iostream.h>
namespace Gabi {
typedef long FmtFlags ;
static int const eof = EOF ;
}

I would consider what you have written as a perfect example as to why
#ifdef is not appropriate to production code. You can't really tell me
that this is maintainable.

I will admit, howeever, that in this case, where there are exactly two
really distinct versions (GB_iostd is defined in another, system
dependant header, according to whether the iostreams are in std:: or
not), I would consider using an #ifdef on non Unix systems. (On Unix
systems, all of the "ios.hh" in the system dependant directories are
links to one of two master files. So there are only the two master
files to maintain.)

Finally, in production code, I just use <iostream.h>, which works pretty
much everywhere, even if it isn't standard.

> I feel that #ifdef (and #if) have valid places in production code.

Maybe, but I've yet to see one.

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

unread,
Oct 1, 2002, 1:09:34 PM10/1/02
to
Gabriel Dos Reis <g...@soliton.integrable-solutions.net> wrote in message
news:<m3smzs7...@soliton.integrable-solutions.net>...
> ka...@gabi-soft.de (James Kanze) writes:

> | - One system supports features that the other system lacks. If
> | you need to target both systems, you don't use these features.
> | It's as simple as that.

> As a corollary, a C++ implementation targetting different plateforms
> should not support (and use) multithreading facilities on system X
> (that does offer them) just because system Y doesn't have them. <g>

Can you give me an example of where a single program might be either
single threaded or multi-threaded, depending on where it is running? In
practice, multi-threading results in serious modifications in the high
level design, and the mutli-threaded and the single threaded versions of
the program will be two different programs. Probably using a lot of the
same classes, but two different programs, none the less.

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

unread,
Oct 1, 2002, 1:10:12 PM10/1/02
to
a980...@unet.univie.ac.at (Thomas Mang) wrote in message
news:<c9ab3170.02093...@posting.google.com>...

> ka...@gabi-soft.de (James Kanze) wrote in message

> > I don't think I've ever used an #ifdef in production code. There
> > are two types of differences between systems:

> > - One system supports features that the other system lacks. If
> > you need to target both systems, you don't use these features.
> > It's as simple as that.

> What do you do when one feature is implemented by one of your
> compilers, and the other isn't (although standard conforming)?

You don't use it. After all, you must implement the semantics without
the feature anyway. And why maintain two versions of code which does
exactly the same thing?

> There are hundreds (even more likely, thousands) of those little
> compiler bugs around. I think the "write it in standard C++, so it is
> 100% portable"

I don't think anyone can accuse me of having said that. I who have
posted that <iostream.h> is currently still more portable than
<iostream>.

> holds only true if you make use of not more than, say, the "basic"
> functionality of C++ (I can, certainly, not define what this is.
> Probably the stuff treated in the first chapters of beginners books).
> I would not dare to use templates, if 100% portability is an issue.

Sure you can. Today, at least. You can't use member templates, and
there is a lot of other things you can't do with templates, but basic,
straightforeward use of templates works pretty much everywhere today.

> What, other than conditional compilation using #if and its associates,
> is your solution for this problem ?

See some of my other answers. And give me a concrete problem: my
statement was that I have never encountered a case where I was even
tempted to use an #ifdef, not that such cannot exist. In practice, I
have a fair amount of experience, and I suspect that if I haven't
encountered such a case, they must be pretty rare. But I can only judge
given concrete examples.

> Don't misunderstand me, I hate this

> #if defined xxxx_BUG

> #else

> #endif

> too. If you have a good solution to avoid this, please tell us.

> I think not using these features is inacceptable in many cases.
> Taking out of code everything that doesn't compile on the one or other
> system would leave me with the "basic" C++ mentioned above. And then I
> wouldn't use C++ anymore.

In application code, I can see only two possibilities:

- The functionality using the new features is part of the
requirements, and you have to implement it without the new features
anyway, for the compilers which don't support them. In this case,
why maintain two versions, when there is one that will work
everywhere. The one that will work everywhere might be less elegant
and more complicated, but since you need to implement it anyway...

- The functionality using the new features is not required. In that
case, just don't implement it, anywhere.

This latter statement obviously only applies at the application level;
some one providing a basic library will obviously want to provide
functionality requiring member templates, even if that functionality
cannot be used on systems which don't support member templates. But
even for basic libraries, I suspect that there are very few such cases.

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

unread,
Oct 1, 2002, 5:22:08 PM10/1/02
to
Gerhard Menzl <gerhar...@sea.ericsson.se> wrote in message
news:<3D986697...@sea.ericsson.se>...
> Jean-Marc Bourguet wrote:

> > In a header workaroud.h declare a macro

> > REPEATED_DEFAULT_TEMPLATE_ARGUMENTS

> > then and use

> > template <class Traits REPEATED_DEFAULT_TEMPLATE_ARGUMENTS(= > DefaultTraits) > X...

> > Personnaly I don't really care if workaroud.h is full of #ifdef or
> > if there are as many versions as system/compilers pairs as needed.
> > That'd probably depend on the build environment and other things.

> Personally, I find this rather unreadable, especially considering that
> it also uglifies and obscures the code for the conforming case. A
> judiciously used #ifdef is a lot easier to understand and maintain.

The understanding is probably a question of habit. The #ifdef has the
advantage of using only standard C++ mechanisms locally, so any C++
should be able to understand it immediately. But if the macro solution
is associated with a naming convention that tells you the what and the
why, it can be just as readable to people familiar with the tradition.

With regards to the maintainability, on the other hand, I can't quite
follow you. With local #ifdef, you have to write something like:

#if XXX
template< class Traits >
#else
template< class Traits = blah >
#endif

If you add an additional argument, or change anything else in the given
line, you have to modify both lines. That seems like more maintenance
overhead to me.

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

JKB

unread,
Oct 1, 2002, 5:23:17 PM10/1/02
to
"James Kanze" <ka...@gabi-soft.de> wrote

> I don't think I've ever used an #ifdef in production code.

How do you handle the situation where a facility is present on two
platforms, but presented differently? A simple example: case-insensitive
string compare is provided by Windows and Linux, but they're called
different things. I write:

int compare_nocase(const char* L, const char* R)
{
#ifdef WIN32
return ::stricmp(L,R);
#endif

#ifdef LINUX
return ::strcasecmp(L,R);
#endif
}

I've also seen this done by #defining one as the other, but even then one
would conditionally compile the define.


-- jkb

Hyman Rosen

unread,
Oct 1, 2002, 7:02:22 PM10/1/02
to
JKB wrote:
> How do you handle the situation where a facility is present on two
> platforms, but presented differently?

By having two separate directories which build into libraries,
one for each platform, and linking with the appropriate one.

> A simple example: case-insensitive string compare is provided by
> Windows and Linux, but they're called different things. I write:

I write:

Linux/cncase.cpp:
int compare_nocase(const char *l, const char *r)
{ return ::stricmp(l, r); }

Windows/cncase.cpp:
int compare_nocase(const char *l, const char *r)
{ return ::strcasecmp(l, r); }

Thomas Mang

unread,
Oct 2, 2002, 5:46:37 AM10/2/02
to
ka...@gabi-soft.de (James Kanze) wrote in message news:<d6651fb6.02100...@posting.google.com>...

> a980...@unet.univie.ac.at (Thomas Mang) wrote in message
> news:<c9ab3170.02093...@posting.google.com>...
> > ka...@gabi-soft.de (James Kanze) wrote in message
>
> > > I don't think I've ever used an #ifdef in production code. There
> > > are two types of differences between systems:
>
> > > - One system supports features that the other system lacks. If
> > > you need to target both systems, you don't use these features.
> > > It's as simple as that.
>
> > What do you do when one feature is implemented by one of your
> > compilers, and the other isn't (although standard conforming)?
>
> You don't use it. After all, you must implement the semantics without
> the feature anyway. And why maintain two versions of code which does
> exactly the same thing?
>
> > There are hundreds (even more likely, thousands) of those little
> > compiler bugs around. I think the "write it in standard C++, so it is
> > 100% portable"
>
> I don't think anyone can accuse me of having said that. I who have
> posted that <iostream.h> is currently still more portable than
> <iostream>.

I haven't accused you of saying that (you didn't).

I think today there are lots of features not mentioned explicitly in
the standard, e.g. such as that sizeof(void *) > sizeof(char), that
are more or less true on every system(might be not true for toasters,
but most of us do not program bread heaters).
OTOH, using many other features which are standard-defined (or just
writing innocent looking code) can yield, well say, undefined compiler
error messages.

>
> > holds only true if you make use of not more than, say, the "basic"
> > functionality of C++ (I can, certainly, not define what this is.
> > Probably the stuff treated in the first chapters of beginners books).
> > I would not dare to use templates, if 100% portability is an issue.
>
> Sure you can. Today, at least. You can't use member templates, and
> there is a lot of other things you can't do with templates, but basic,
> straightforeward use of templates works pretty much everywhere today.
>

Doesn't this implicitly encourage compiler writers NOT to become
standard - conforming?
I think many managers of compiler software will be tempted to say
something like "nobody uses it, so don't spend money on developing
it".
Today compilers offer really nifty optimizations, and other stuff they
don't have to develop (according to the standard, such as more
keywords....).

I'd prefer compilers which FIRST implement the standard features, and
THEN improve their code further.(After all, I do not consider speed a
critical factor in most apps).

And everything that releases pressure on compiler manufacturers to
implement a standard conforming implementation is, for me, a walk in
the wrong direction.


best regards,

Thomas

Jean-Marc Bourguet

unread,
Oct 2, 2002, 5:48:40 AM10/2/02
to
Gerhard Menzl <gerhar...@sea.ericsson.se> writes:

> Jean-Marc Bourguet wrote:
>
> > In a header workaroud.h declare a macro
> >
> > REPEATED_DEFAULT_TEMPLATE_ARGUMENTS
> >
> > then and use
> >
> > template <class Traits REPEATED_DEFAULT_TEMPLATE_ARGUMENTS(= > DefaultTraits) > X...
> >
> > Personnaly I don't really care if workaroud.h is full of #ifdef or if
> > there are as many versions as system/compilers pairs as needed.
> > That'd probably depend on the build environment and other things.
>
> Personally, I find this rather unreadable, especially considering
> that it also uglifies and obscures the code for the conforming
> case.

I don't find this more unreadable or more ugly than most C++ idioms.
You just have to know about it. It's similarity with the common way
of handling prototypes in ISO C while still beeing able to compile
with K&R C should make it obvious to quite a few people.

The only problem is knowning why it is needed.

> A judiciously used #ifdef is a lot easier to understand and
> maintain.

I just wonder why the ifdef was not used for the prototype at the said
transition? Probably because the ifdef means that there is
duplication of code and duplication not checked by the compiler is a
common source of problems for maintenance.

The ifdef solution has another maintenance problem: the condition
tested risks to become more and more complicated, even if at the start
there was only one macro tested.

Yours,

--
Jean-Marc

Gabriel Dos Reis

unread,
Oct 2, 2002, 5:58:40 AM10/2/02
to
ka...@gabi-soft.de (James Kanze) writes:

> Gabriel Dos Reis <g...@soliton.integrable-solutions.net> wrote in message
> news:<m3smzs7...@soliton.integrable-solutions.net>...
> > ka...@gabi-soft.de (James Kanze) writes:
>
> > | - One system supports features that the other system lacks. If
> > | you need to target both systems, you don't use these features.
> > | It's as simple as that.
>
> > As a corollary, a C++ implementation targetting different plateforms
> > should not support (and use) multithreading facilities on system X
> > (that does offer them) just because system Y doesn't have them. <g>
>
> Can you give me an example of where a single program might be either
> single threaded or multi-threaded, depending on where it is running?

I was quite careful in wording my previous message. I was talking of
a C++ _implementation_ supporting and using multithreading facilities.

That being recalled, since you asked for an example (although the
example you asked for is quite irrelevant to my message) I would just
point out the implementation of std::allocator<> component found in
the GNU C++ implementation which takes advantages of multithreading
facilities when present -- there are certainly better examples, for
the sake of existence it suffices.

> In
> practice, multi-threading results in serious modifications in the high
> level design, and the mutli-threaded and the single threaded versions of
> the program will be two different programs.

Did you miss *C++ implememtation* in my previous message? Does a C++
implementation need to be a complete program?

--
Gabriel Dos Reis, g...@integrable-solutions.net

Lyle H. Gray

unread,
Oct 2, 2002, 3:37:42 PM10/2/02
to
> "James Kanze" <ka...@gabi-soft.de> wrote
> > I don't think I've ever used an #ifdef in production code.
>
> How do you handle the situation where a facility is present on two
> platforms, but presented differently?

I'm not sure this is what James meant, but we've already covered that

#ifdef CREDIT

can be (and is) represented by

#if defined(CREDIT)

So, your simple example:

> int compare_nocase(const char* L, const char* R)
> {
> #ifdef WIN32
> return ::stricmp(L,R);
> #endif
>
> #ifdef LINUX
> return ::strcasecmp(L,R);
> #endif
> }

would become

int compare_nocase(const char* L, const char* R)
{

#if defined(WIN32)
return ::stricmp(L,R);
#endif

#if defined(LINUX)
return ::strcasecmp(L,R);
#endif
}

or, more compactly

int compare_nocase(const char* L, const char* R)
{

#if defined(WIN32)
return ::stricmp(L,R);
#elif defined(LINUX)
return ::strcasecmp(L,R);
#endif

Gerhard Menzl

unread,
Oct 2, 2002, 3:38:41 PM10/2/02
to
James Kanze wrote with regard to whether:


template <class Traits REPEATED_DEFAULT_TEMPLATE_ARGUMENTS(=
DefaultTraits) > X...

or

#ifdef DEFAULT_TEMPLATE_ARGUMENT_RESPECIFICATION_BUG
template <class Traits = DefaultTraits>;
#else
template <class Traits>;
#endif

is more readable and easier to maintain:

> The understanding is probably a question of habit. The #ifdef has
> the advantage of using only standard C++ mechanisms locally, so any
> C++ should be able to understand it immediately. But if the macro
> solution is associated with a naming convention that tells you the
> what and the why, it can be just as readable to people familiar with
> the tradition.

You certainly have a point here. However, the familiarity of a
programming idiom is a crucial factor when it comes to maintenance. Of
course, this does not mean that bad habits should be kept just because
that's what people are used to.

As for expressing your intent using descriptive names: I am an active
advocate of it, but it has its limits. There are things so complicated
(especially when it comes to bugs in the implementation of
template-related features) that a single, clever identifier just won't
cut it.



> With regards to the maintainability, on the other hand, I can't quite
> follow you. With local #ifdef, you have to write something like:
>
> #if XXX
> template< class Traits >
> #else
> template< class Traits = blah >
> #endif
>
> If you add an additional argument, or change anything else in the
> given line, you have to modify both lines. That seems like more
> maintenance overhead to me.

I consider the overhead negligible because the required change is still
very local, and the need to apply it to both lines is obvious. The
alternative still requires a compiler-dependent #ifdef, but it is
located in a different file, and it requires the maintenance programmer
to locate that file and open it in order to understand that

REPEATED_DEFAULT_TEMPLATE_ARGUMENTS(=DefaultTraits)

evaluates to nothing except for the non-conforming compiler. In
contrast, the lines between #if and #else, or #else and #endif,
respectively, are unobscured, immediately intelligible C++.

Apart, from that, the above was just one example. It is not hard to come
up with other examples that are not easily solved with a single macro.

Gerhard Menzl

Gennaro Prota

unread,
Oct 3, 2002, 5:32:37 AM10/3/02
to
On 1 Oct 2002 13:08:32 -0400, ka...@gabi-soft.de (James Kanze) wrote:

>Gabriel Dos Reis <g...@soliton.integrable-solutions.net> wrote

>> Gennaro Prota <gennar...@yahoo.com> writes:
>
>> [...]
>
>> | I suppose in such a case Mr. Kanze would simply include the header
>> | with the definition and give up using forward declarations. But
>> | that's a bad service to people who have serious compilers: they have
>> | to pay for a defect of someone else.
>
>> Maybe in such case, Mr. Kanze won't support more than one C++
>> implementation ;-)
>
>More likely, I'd say that default template arguments are a feature that
>isn't ripe enough for production code, and not use them.

Over-generalized opinion, IMHO.

>Or adopt a
>solution along the lines of what Jean-Marc suggested.

Ok for me. As long as you accept/admit that you still have a #if/#else
for the definition of the macro.

>Or even decide
>that the situation justified an exception to the rule: I'm a pragmatic
>person.

Thanks :-)

>However, as I have pointed out, my original statement concerned my
>actual experience. I have no experience in general purpose libraries,
>which must be delivered to many different customers. So maybe my
>decision would be different in such a case.
>
>I don't quite understand that when I make a statement openly concerning
>my own experience ("I don't think I've ever used an #ifdef in production
>code."), people take it as an absolute rule.

I think that's a drawback of being a well-known expert. Had I said the
same thing, do you think it would have arisen all this dust? :-)

>I think that #ifdef are
>something to avoid if at all possible. But like all rules, that is
>subject to the meta-rule that it can be violated if the circumstances
>justify. In this case, all I said was that in my own experience, I've
>never encountered a case where the circumstances justified it. As a
>statement, it has some informational value, because I have a fair amount
>of experience, in both commercial and industrial domaines. But it is
>hardly an absolute, since there are other domains (general purpose
>libraries, game software, numerics) in which I've no experience; since
>even in the domains I have experience, there might be particular cases
>that I have experienced; and since I rather nuanced the statement
>anywhere "I don't think I've ever ...". My understanding of English is
>that there is a significant difference between "I don't think I've
>ever ..." and "No one must ever ...".

Ok. I see some grudge in your words which is probably due to my phrase
"I suppose Mr. Kanze..."; actually that phrase was meant to say that I
wasn't sure about what you would have done in such a case, and that I
was just guessing. No intent to be disrespectful on my part, as I
tried to make clear from that 'Mr.' in front of your name (intended as
a sign of respect). However I'm far from sure that I expressed in a
way that achieved my goal, it's very likely that to a native speaker
the phrase gives a completely different impression.

{The trouble is that an insertion of an honorific when one would not
normally use it can be taken with the exact opposite meaning. English is
a confusing language, its close similarity with American makes it more
so:-)
-mod/fwg}

Now for a general remark: guidelines are "means", not ends. Take e.g.
the "test for features, not for systems". Its reason to exist is in
the fact that (among other things) the same system may be
upgraded/fixed in the future making your implication "if this is
system XYZ then feature KXY is missing" suddenly become incorrect. In
other words: it's an issue of maintainance/future validity of the
code. Of what we could call the two *parts* of a guideline, i.e. the
"mean" and the "end", the first one is what the common language calls
"guideline", however that's IMHO the less important part. The most
important is the end. And, as programmers, we must break the guideline
if there are better means to achieve the same end (for some
definition/opinion of "better" - that's the true problem).

Now, let's consider this default template arguments example:

// in x_fwd.hpp
template <class T = int, class U = std::allocator<T> > class X;

// in x.hpp
#if .... // buggy compiler
template <class T = int, class U = std::allocator<T> >
#else
template <class T, class U>

class X { /* ... */ };


In this case we could also choose to not use default arguments (which
I dislike for the reasons I said elsewhere), or hiding that #if/#else
behind a macro:

# if .... // buggy compiler
# define DEF_ARGS_IN_THE_DEFINITION class T = int, class U =
std::allocator<T>
# else
# define DEF_ARGS_IN_THE_DEFINITION class T, class U
# endif


That's ok for me, as long as nobody complaints about the use of a
macro in its own (macros are evil... macros don't respect scope...
etc...). As an as much questionable device you could decide to #undef
the macro at the end of x.hpp. Note also that you can choose to
#define the macro in x.hpp (so that it remains 'local' to that file),
but if you do so then someone could tell you that there's the problem
of keeping it synchronous to x_fwd.hpp. If you want to have one place
where the default arguments are specified without having a macro in
x_fwd.hpp that you can't #undef at the end of the same file then you
have probably to use some helper template, because the second default
depends on the first argument:


// in x_fwd.hpp
#include <memory>

namespace workarounds {
typedef int first_def_arg;

template <typename T>
struct second_arg {
typedef std::allocator<T> value;
};
}

template <typename T = workarounds::first_def_arg, typename U =
typename workarounds::second_arg<T>::value>
class X;

// in x.hpp (untested)
# if ... // buggy compiler
# define DEF_ARGS_IN_THE_DEFINITION typename T =
workarounds::first_def_arg, typename U = typename
workarounds::second_arg<T>::value

# else
# define DEF_ARGS_IN_THE_DEFINITION typename T, typename U
# endif

template <DEF_ARGS_IN_THE_DEFINITION>
class X { /*...*/ };


That's likely to incur in some other compiler bugs however and,
considering how unlikely is that one can change the default arguments
of a template when he already has some client code that uses it, it's
more trouble than the problem it solves. Nothing guarantees that
everybody has the same opinion though.

Note how I'm pointing out the fact that when you work in team you have
to satisfy others too. Actually the reason why I have used a "direct"
#if/#else for dynamic_bitset is the sort of fear that everybody have
for macros. They will tell me, I thought, that macros are best
avoided. To be honest I have used a macro anyway, i.e. the highly
readable (;-) BOOST_WORKAROUND_REPEAT_DEFAULT_TEMPLATE_ARGUMENTS but
that's for the good reason, we all know (As an aside I think that the
rule that long names are *always* clearer is quite stupid too. But let
us not put too many irons in the fire).

IMHO, that (guessed but, you know, possible) objection means confusing
the mean for the goal. However one has to come to a compromise with
the opinion of others of course.

Granted, as you say there's a meta-rule that says a rule can be broken
if you can justify the reasons for breaking; but everything depends on
what other things about "justifying". I think for instance that main()
should have a return statement, and there's no reason for it to be a
special case. Also I think that prohibiting (void*)0 to be a null
pointer constant is a silly and gratuitous incompatibility with C, and
that the "rationale" often quoted for not allowing forward
declarations of enums is silly. However there are top-level experts
that would kill me for these assertions. As you see, it's a matter of
opinions (despite the fact that we try to make everything appear as
pure, objective, incontrovertible logic). I'm sure there's people
around that is convinced of some incontestable reason why #ifndef
should be used for include guards instead of #if !defined, and maybe
that's one of the issues one can arise to beat the record of the
longest c.l.c++.m thread too :-)

Of course all this rigmarole is not addressed to you (I think you know
how in high esteem I hold you), that's clear. It's just to point out
how many opinions are often passed of as justified good (and
universal) rules.

In general I suspect of all dogmatic assertions.

Note that the reason why I accept the macro solution above is not that
we avoid #if-s (we don't, and also have an additional macro) but
because it allows me to achieve my goal: supporting all my target
compilers without depriving the users who are not affected by the bug
of the benefits of the forward declaration. The con of having a macro
is IMHO balanced (enough) by having a more readable template
definition, so that I'm neutral between this solution and the one I
choosed for dynamic_bitset.

It's worth noting that in other cases the goal of having a single
modification point, together with the fact that the workaround
requires a manipulation of tokens (something that only the
preprocessing phase can do), leaves you with two choices only: an
explicit chain of #if/#else or a macro. Then it depends, all the other
things being equal, on the context (even on whether there are other
preprocessing directives near the point of application, for instance)
which is clearer.


Genny.

Gerhard Menzl

unread,
Oct 3, 2002, 5:37:26 AM10/3/02
to
James Kanze wrote in reply to an example involving compiler differences
with regard to default template arguments:

> The solution in application code is simple: don't use default
> template arguments.

and:

> Forgo default template arguments altogether. IMHO, the answer here
> is simple. New features are a potential source of problems. Don't
> use them until you know they work everywhere.

I had an inkling that something along these lines was going to appear in
your reply. :-) And as with most of the rules which to proclaim you have
a reputation for, I agree in theory and in principle. The same compiler
that implements default template arguments incorrectly also has shaky
support for exceptions and namespaces, so we don't use them, even though
that means that I cannot apply most of what is discussed here or in Herb
Sutter's books in my daily work. Life can be tough.

On the other hand, if you were to obey your rule rigorously and without
exceptions (pun not intended), you could easily end up forgoing
virtually all C++ features that are not in C. Or even more than that -
said compiler was found to have problems implementing static locals
correctly, for example. You also have to take into account that compiler
incompatibilities often remain undetected before large parts of code
have been written. If you claim that this is impossible as long as a
proper development process is followed (as I could well imagine you
saying :-) ), consider the case of porting an existing application to a
new platform that requires an older compiler. Would you advocate
rewriting existing code for the sake of an aberrant newcomer? Even if
you know its EDG-based successor is just around the corner? I would
think that the cost of bridging the compatibility gap with an #ifdef is
far outweighed by the cost of dumbing down (and recompiling, and
regression-testing) existing and working code. It is simply not possible
always to determine in advance which features are going to work
everywhere.

> I'll admit that this is one of the limit cases, however, since both
> compilers offer the functionality, just in different forms (and the
> user code doesn't see the difference). Still, I suspect that if you
> need to support two different variants of a new feature, the need
> will arise to support a compiler which doesn't support the feature at
> all, and you'll have to do without anyway.

This argument, when taken to the extreme, would prohibit the use of C++
in production code altogether, particularly in the embedded systems
domain. Not really an option when your job is to maintain and enhance an
existing C++ application.

In addition, this is not just about missing language features. In
practice, #ifdefs can be a reasonable and cost-effective way around
compiler bugs. Compilers usually don't come with a big, red sticker
"Warning! Cannot handle anything resembling template<class T> ...", so
this is nothing you can really anticipate.

> An STL implementation is what I would call a general library. As I
> said above, I'm less certain about this, because I have no real
> experience with it. At the very least, I, as a user, would hate to
> be deprived of the template member functions because some of the
> library users (but not me) have to compile with a compiler which
> doesn't support member templates.

My job mainly involves writing general libraries for the application
developers (if not as general as the STL), so maybe this explains our
different views.

> As usual, there is no black and white, only different shades of gray.
> From what you say, I think you would agree that #ifdef within a
> function is a horror, to be avoided at all costs. Generally speaking
> I would prefer to avoid the #ifdef everywhere. But I recognize that
> some are worse than others.
>
> Like all of the rules in the coding guidelines, this one is subject
> to the meta-rule that it can be broken if you can justify the reasons
> for breaking it.

I think we can agree to agree here. I also think there is a delicate
balance between not rushing into the use of every new-fangled language
on the one hand and not fettering your code with the lowest common
denominator from twenty years past for all times on the other.

Gerhard Menzl

Gerhard Menzl

unread,
Oct 3, 2002, 5:38:06 AM10/3/02
to
Jean-Marc Bourguet wrote regarding:

template <class Traits
REPEATED_DEFAULT_TEMPLATE_ARGUMENTS(= DefaultTraits) X;

> I don't find this more unreadable or more ugly than most C++ idioms.
> You just have to know about it. It's similarity with the common way
> of handling prototypes in ISO C while still beeing able to compile
> with K&R C should make it obvious to quite a few people.
>
> The only problem is knowning why it is needed.

and, further down:

> I just wonder why the ifdef was not used for the prototype at the
> said transition? Probably because the ifdef means that there is
> duplication of code and duplication not checked by the compiler is a
> common source of problems for maintenance.
>
> The ifdef solution has another maintenance problem: the condition
> tested risks to become more and more complicated, even if at the
> start there was only one macro tested.

You need the test anyway, either as an #ifdef in the header that defines
REPEATED_DEFAULT_TEMPLATE_ARGUMENTS, or, even further removed from the
code, as an %ifdef in the makefile that selects between two versions of
that header. Thus what you gain with avoiding code duplication you pay
for with decreased locality of reference, which in turn makes
maintenance harder. I think it's a trade-off; there isn't one true
approach. If the code difference affects a single line, #ifdef is
probably the most efficient solution, but as the code diverges more and
more, separate, platform-specific files tend to win.

Gerhard Menzl

James Kanze

unread,
Oct 3, 2002, 5:40:44 AM10/3/02
to
a980...@unet.univie.ac.at (Thomas Mang) wrote in message
news:<c9ab3170.0210...@posting.google.com>...

> ka...@gabi-soft.de (James Kanze) wrote in message
> news:<d6651fb6.02100...@posting.google.com>...

> > Sure you can. Today, at least. You can't use member templates,
> > and there is a lot of other things you can't do with templates, but
> > basic, straightforeward use of templates works pretty much
> > everywhere today.

> Doesn't this implicitly encourage compiler writers NOT to become
> standard - conforming?

I don't think so. Not directly, at any rate. I doubt many compiler
writers ever look at my code, to see which features I'm actually using,
and which ones I'm not.

Of course, just because you don't use a feature yet, you shouldn't stop
asking for it. Here, and anywhere else you can make yourself heard.

And there is an indirect risk. If instead of asking you, your bosses
look at what you are currently using to determine what to look for in
the next compiler, they might inform the compiler implementors that the
new features aren't important. I'm tempted to say that if that is the
case, they probably have pointy hair, too, and that it is time to look
for a new job. But I realize that the situation is not quite that
simple. But still, there should be some lines of communication open
between you and your bosses.

> I think many managers of compiler software will be tempted to say
> something like "nobody uses it, so don't spend money on developing
> it".

Nobody used Windows when all we had was MS-DOS. Nobody used Windows
2000 when all we had was Windows 98. Etc., etc.

My impression is that the vendors (or at least some vendors) are
constantly looking for something new to implement, if only to sell you a
new version.

> Today compilers offer really nifty optimizations, and other stuff they
> don't have to develop (according to the standard, such as more
> keywords....).

A lot of compilers offer really nifty optimizations because their
customers want them:-).

> I'd prefer compilers which FIRST implement the standard features, and
> THEN improve their code further.(After all, I do not consider speed a
> critical factor in most apps).

I agree, but the guy next door who is working on a CPU intensive
application which only uses double[] probably doesn't.

Historically, I fear that the usual order of priorities has been:

speed
new features
robustness

As far as I'm concerned, that is 100% backwards. But I don't think not
using a feature because it isn't there is a reason for this.

> And everything that releases pressure on compiler manufacturers to
> implement a standard conforming implementation is, for me, a walk in
> the wrong direction.

If you really think that maintaining two versions of the same code
(which the compiler manufacturer will never see) will somehow increase
the chance of your compilers becoming standards conform, go for it.
(And I'm not being 100% cynical -- I can imagine environments where
showing a boss a lot of code loaded with #ifdef, and explaining to him
that you wouldn't need all this if compiler X would get their shit in
order, might be the only way to get your company to apply presure on the
vendor. Until now, however, I guess I've been lucky, and all my bosses
have asked me what we needed, and believed my answer without looking at
the code.)

--
James Kanze mailto:jka...@caicheuvreux.com

Conseils en informatique oriente objet/
Beratung in objektorientierter Datenverarbeitung

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

David Cattarin

unread,
Oct 3, 2002, 5:42:42 AM10/3/02
to
ka...@gabi-soft.de (James Kanze) wrote in message news:<d6651fb6.02100...@posting.google.com>...

> dit...@ix.netcom.com (David Cattarin) wrote in message
> news:<30869baf.02092...@posting.google.com>...
> > ka...@gabi-soft.de (James Kanze) wrote in message
> > news:<d6651fb6.02092...@posting.google.com>...
> > [snip]
> > > I don't think I've ever used an #ifdef in production code. There
> are
> > > two types of differences between systems:
>
> > > - One system supports features that the other system lacks. If
> you
> > > need to target both systems, you don't use these features.
> It's as
> > > simple as that.
>
> > No, it's not. That's the problem with generalizations. What happens
> > when you *have* to have the feature due to requirements? Then, on the
> > offending platforms, you have to simulate it. You may encapulate the
> > problem in a file/class/function, but at some point, you might very
> > well have to use #ifdef to choose between the provided feature and the
> > simulated one.
>
> Why not use the "simulated" solution everywhere? Why maintain two
> solutions, when one would be enough?

Performance is a big reason.

> And what are the requirements that are formulated at such implementation
> detail levels?

Here's a for instance. I deal mostly with telecom protocols. By
supporting a particular protocol it forces you to deal with whatever
data types are contained in the protocol. In some instances, that
means having to support BCD encoded numbers. There are some systems
where encoding & decoding strings is provided. On others there is not.
Why shouldn't I use the (presumably) fast version when it is
available?

>
> > > - Both systems support the same functionnality, but in different
> > > ways. The obvious examples are sockets or threads. And the
> obvious
> > > solution is to encapsulate the functionality in an object, or
> if it
> > > is really, really small, in macros. (I used macros for a while
> to
> > > use the new style casts where they were supported, the old
> style
> > > otherwise.)
>
> > This isn't really true either. Case in point: compiler bugs. I
> > recently found a bizarre problem with certain HP compilers. The
> > compiler would fail to compile valid switch code. It claimed that the
> > break was incorrect. The only way to work around this was to #ifdef
> > the break and replace it with a goto for the "offending" lines.
>
> Why do you need the #ifdef? Wouldn't the goto work with the other
> compilers?

Yes it would, but the point is that the goto was a work around for
this particular compiler. It was only inserted into the production
code so that the port to this platform could be completed. Presumably,
once the compiler is fixed, then the goto can be removed.

IMO, the #ifdef acts as better documentation in this case than a
comment. It emphasizes that the goto is temporary. Once the compiler
is fixed, this code will be removed.

But, if the #ifdef wasn't there, someone would probably forget that
this was a workaround.

> > > Can you show me an example of something else? Where you might
> > > actually want to use an #ifdef in the code. I've never yet
> > > encountered a case where I would want to, although I think I would
> > > resist if I did; I can't think of anything which would make the
> > > code harder to maintain.
>
> > How about #pragmas.
>
> You win:-). They must be worse than #ifdef's.

Yes they are! ;)

> (But I suppose it
> depends on the #pragma. A pragma that turns certain warnings on or off
> shouldn't cause any real problems.

True, but you haven't seen the pages and pages of warnings that are
generated by the M$ compiler when compiling STL code. There are even
some clients that requires code to compile with no warnings. Using
this #pragma is a decent compromise.

> A pragma that changes the semantics
> of legal code will render the program totally unmaintainable, however.)

True. I only use pragmas to make code work correctly. I've had to
maintain a lot of production code, so here's another for instance: In
one piece of code, a developer was using alloca to create variable
sized arrays on the stack. I had to port it to IBM, where alloca is
only "enabled" if either a #pragma is present, or a compiler option is
used. I suggested to the developer to use the #pragma (#ifdef'd for
IBM) in only that file.

>
> > You might want to #ifdef these to avoid confusing a compiler on a
> > different platform. For people doing windows' programming, I'm sure
> > the following construct is familiar:
>
> > #ifdef WIN32
> > # pragma warning ( disable : 4786 ) // warning for truncated
> > debugging info
> > #endif
>
> > This avoids disabling the wrong warning for a different compiler.
>
> Well, it seems strange to me that such a silly warning would be on in
> the first place (or even exist), but who knows. But surely want to
> disable it globally, and the command line is the place for that.

Fair enough, but I don't have control over the company's make system.
Every time I've made a suggestion, there has been days/weeks of
discussion/battle over whether or not my suggestion should be
implemented.

> And if
> only a pragm will do:
>
> #include "SystemPragmas.hh"
>
> with a version of the header for each system, in a system dependant
> directory specified by a -I option in the command line.

Fair enough. That is a reasonable suggestion, but I haven't had a
chance to work out what I'd put there.

> Note that I'm not really trying to be dogmatic here, but to indicate
> that other solutions exist, and that except in rare cases, they will be
> preferable.

I do like seeing different viewpoints in these discussions. But, I
think even you recognize that there are cases, maybe not so rare, whre
#ifdef is useful.

> > How about compilers with different levels of standards compliance. I
> > use the following code to get around problems with ostream formatting.

[snip]


>
> At present, my application level code only includes my own IO headers:
> "iostream.hh", "istream.hh", etc. Again, these files exist in different
> versions, in different directories, and the version used is selected by
> a -I option in the command line. The file "ios.hh" is either:

We have a development policy that forbids the use of extensions like
".hh".

>
> #include <ios>
> namespace Gabi {
> typedef GB_iostd::ios_base::fmtflags FmtFlags ;
> static int const eof = GB_iostd::char_traits<char>::eof() ;
> }
>
> or:
>
> #include <iostream.h>
> namespace Gabi {
> typedef long FmtFlags ;
> static int const eof = EOF ;
> }

I do like that, but it might not be so easy to get others to use the
same approach.

> I would consider what you have written as a perfect example as to why
> #ifdef is not appropriate to production code. You can't really tell me
> that this is maintainable.

It's been in production code for 3 years and has been ported to 9
platforms. It works just fine, even if it is ugly. I'll admit that I
chose the expedient solution.

Speaking of production code, have you taken a look at any STL
implementations? I haven't seen one that doesn't liberally use
#ifdefs.

[snip]


> > I feel that #ifdef (and #if) have valid places in production code.
>
> Maybe, but I've yet to see one.

How about include guards?

Anyway, maybe I can convince you that there are *some* uses. ;)

Dave

James Kanze

unread,
Oct 3, 2002, 5:43:34 AM10/3/02
to
Gabriel Dos Reis <g...@integrable-solutions.net> wrote in message
news:<m37kh1j...@uniton.integrable-solutions.net>...
> ka...@gabi-soft.de (James Kanze) writes:

> > Gabriel Dos Reis <g...@soliton.integrable-solutions.net> wrote in message
> > news:<m3smzs7...@soliton.integrable-solutions.net>...
> > > ka...@gabi-soft.de (James Kanze) writes:

> > > | - One system supports features that the other system lacks.
> > > | If you need to target both systems, you don't use these
> > > | features. It's as simple as that.

> > > As a corollary, a C++ implementation targetting different
> > > plateforms should not support (and use) multithreading facilities
> > > on system X (that does offer them) just because system Y doesn't
> > > have them. <g>

> > Can you give me an example of where a single program might be
> > either single threaded or multi-threaded, depending on where it is
> > running?

Last things first...

> Did you miss *C++ implememtation* in my previous message?

Yes. I recognize that e.g. library implementers face a different set of
problems than I do, and that their solutions may be different. While I
still suspect that most of the differences can be glossed over by some
fancy macros and empty classes (e.g. creating an instance of a lock
object even in the single threaded version, knowing that the single
threaded version of the lock object is trivial and empty), I've not
enough experience to be sure that this is always the case.

With regards to a complete C++ implementation, I think that it is only a
library issue. With regards to the compiler and code generation, you
probably want to handle the differences at run-time, according to
whether the user requests multi-threading or not. With regards to the
true library part, of course, you deliver two libraries, but you
probably want to use common source for them. And of course, with
templates, you have to deliver the sources anyway.

For starters:

- I will suppose that the library won't actually start any threads on
its own (but see below).

- Furthermore, I will suppose that any pthread_mutex type objects have
been encapsulated by a class (which obviously isn't present in the
single threaded version).

- Given that, I would provide a macro which is used to define and/or
declare the mutex objects. A macro which resolves to nothing in the
case of the single threaded version. In this manner, I don't need
#ifdef's around the declaration of the mutex object in the class
definitions, etc.; I write the macro, and get what is needed.

- For the actual locking, I suppose you are using a class (RAII). In
this case, I would consider using the class in the same fashion in
the single threaded version, with the difference that the class then
does nothing. I'm not sure that this can be made to work, however,
as the class constructor will normally require a parameter, which
you don't have in the single threaded version. Again, wrapping the
declaration in a macro should do the trick.

I'm not sure if this would cover all cases, but it would go a long way
toward it.

> Does a C++ implementation need to be a complete program?

It's generally several complete programs:-). Plus the libraries.

> I was quite careful in wording my previous message. I was talking of
> a C++ _implementation_ supporting and using multithreading facilities.

Yes, and I missed that part. Sorry.

> That being recalled, since you asked for an example (although the
> example you asked for is quite irrelevant to my message) I would just
> point out the implementation of std::allocator<> component found in
> the GNU C++ implementation which takes advantages of multithreading
> facilities when present -- there are certainly better examples, for
> the sake of existence it suffices.

Actually, the allocator is IMHO a good example supporting my position.
A good multithreaded allocator will use different algorithms than a
single threaded one, so you will simply maintain two completely
different implementations, in two completely different files.

--
James Kanze mailto:jka...@caicheuvreux.com

Conseils en informatique oriente objet/
Beratung in objektorientierter Datenverarbeitung

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

unread,
Oct 3, 2002, 9:37:02 AM10/3/02
to
Gerhard Menzl <gerhar...@sea.ericsson.se> wrote in message
news:<3D9AEE30...@sea.ericsson.se>...
> Jean-Marc Bourguet wrote regarding:

> template <class Traits
> REPEATED_DEFAULT_TEMPLATE_ARGUMENTS(= DefaultTraits) X;

> > I don't find this more unreadable or more ugly than most C++
> > idioms. You just have to know about it. It's similarity with the
> > common way of handling prototypes in ISO C while still beeing able
> > to compile with K&R C should make it obvious to quite a few people.

> > The only problem is knowning why it is needed.

> and, further down:

> > I just wonder why the ifdef was not used for the prototype at the
> > said transition? Probably because the ifdef means that there is
> > duplication of code and duplication not checked by the compiler is
> > a common source of problems for maintenance.

> > The ifdef solution has another maintenance problem: the condition
> > tested risks to become more and more complicated, even if at the
> > start there was only one macro tested.

> You need the test anyway, either as an #ifdef in the header that
> defines REPEATED_DEFAULT_TEMPLATE_ARGUMENTS, or, even further removed
> from the code, as an %ifdef in the makefile that selects between two
> versions of that header.

Not an ifdef, anywhere, but a variable (which speficies the name of a
sub-directory). If it weren't for the compiler (and non-Unix systems),
this name could be created automatically, by using the output of uname,
with various options.

> Thus what you gain with avoiding code duplication you pay for with
> decreased locality of reference, which in turn makes maintenance
> harder.

Spencer and Collyer speak of it in terms of defining an interface.

There's a trade off here. You don't put all of your code in the
function main, just to maintain locality of reference. You abstract.
All we've done here is abstract part of the compiler dependancies.

> I think it's a trade-off; there isn't one true approach. If the code
> difference affects a single line, #ifdef is probably the most
> efficient solution, but as the code diverges more and more, separate,
> platform-specific files tend to win.

If the #ifdef is purely binary, if you can guarantee that is will remain
so, if it only covers one or two lines, and if it is in the
declarations, then it probably isn't too bad. But that's a lot of
if's. When alternative approaches exist, I prefer to use them.

--
James Kanze mailto:jka...@caicheuvreux.com

Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

unread,
Oct 3, 2002, 9:37:37 AM10/3/02
to
"Lyle H. Gray" <gr...@no.spam.cs.umass.edu> wrote in message
news:<Xns929AC3424E687gr...@199.45.49.11>...

> > "James Kanze" <ka...@gabi-soft.de> wrote
> > > I don't think I've ever used an #ifdef in production code.

> > How do you handle the situation where a facility is present on two
> > platforms, but presented differently?

> I'm not sure this is what James meant, but we've already covered that

> #ifdef CREDIT

> can be (and is) represented by

> #if defined(CREDIT)

Which changes nothing. I wrote #ifdef as a simple contraction for #if,
#ifdef and #ifndef. Conditional compilation is something to be avoided,
if at all possible, and I've found that it generally is possible to
avoid it, even when writing code which must work on a variety of
platforms.

The idea isn't new to me. Many years back, it was already being pushed,
by people like Henry Spencer and Geoff Collyer (see
http://www.cs.umd.edu/users/cml/cstyle/ifdefs.pdf). C++ just makes it
easier (inline functions, for example, and classes).

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Jean-Marc Bourguet

unread,
Oct 3, 2002, 9:41:56 AM10/3/02
to
Gerhard Menzl <gerhar...@sea.ericsson.se> writes:

> You need the test anyway, either as an #ifdef in the header that
> defines REPEATED_DEFAULT_TEMPLATE_ARGUMENTS, or, even further
> removed from the code, as an %ifdef in the makefile that selects
> between two versions of that header.

The version of the header will be selected exactly by the same
mecanism as the compiler. Probably in the same file. That can be a
makefile fragment selected with %ifdef, in an included makefile
fragment, in Imake configuration, in the versionning system
configuration...

> Thus what you gain with avoiding code duplication you pay for with
> decreased locality of reference, which in turn makes maintenance
> harder.

I prefer having all my platform dependend stuff in the same place (or
at least in some restricted set of places) than having them scattered
all along the code. Knowing that to handle all known compiler and
system dependancies I should have only to modify the "sysindep"
library and two makefile fragments which are included in the makefiles
is a good starting point. Now there will be surprises, but they will
be surprises and not something which should have been expected.

> I think it's a trade-off; there isn't one true approach. If the code
> difference affects a single line, #ifdef is probably the most
> efficient solution, but as the code diverges more and more,
> separate, platform-specific files tend to win.

It is always a matter of trade-off. My reaction was to the statement
"it is not possible to handle this case without #ifdef". I showed a
way that I'd prefer to #ifdef in the kind of programs I've worked on.

Obviously this would be over-engineered for a run-once-and-then-
throw-away program. Now for a millions lines program delivered on
several platforms which will probably probably be delivered on
currently not existing platforms where components are reused in other
programs and may outlive the programs they where designed for that's
another matter.

Even if a test occured only in one place, it could be usefull to put
it at the place were other such tests are made, because that's where
people will look for the test. Consistency with existing practice is
an important factor. If in an project such matters are currently
handled with #ifdef, I'll use them and nothing else.

BTW, these are not the only possibilities. Standardizing on one
compiler available on the supported platform (for example g++ or
comeau) is another for solving the issue at hand.

Yours,

--
Jean-Marc

Gennaro Prota

unread,
Oct 3, 2002, 9:44:44 AM10/3/02
to

Francis Glassborow wrote:
>{The trouble is that an insertion of an honorific when one would not
>normally use it can be taken with the exact opposite meaning. English is
>a confusing language, its close similarity with American makes it more
>so:-)
>-mod/fwg}

I see. I suspected that fact after reading Gabriel Dos Reis' reply,
where he repeats the honorific too. Sorry for this misunderstanding.
Actually I thought that using just the name could have been perceived
to be exactly as much disrespectful as using the honorific was. My
apologies to everybody, and to James Kanze in particular.

By the way you all may have an idea of the quality of my English by
reading that 'other things about "justifying"' instead of 'others
think about "justifying"' or that 'choosed' instead of 'chose'.

James Kanze

unread,
Oct 3, 2002, 9:45:06 AM10/3/02
to
Gerhard Menzl <gerhar...@sea.ericsson.se> wrote in message
news:<3D9AB42A...@sea.ericsson.se>...

> or

I was actually speaking of something much more limited. I was
considering the case where you had local coding guidelines which
described (and prescribed) the idiom, and which defined a special naming
convention (say a prefix) which identified it immediately.

I would expect anyone coming on to a project to familiarize himself with
such coding guidelines before doing anything else. Conventions defined
by the guidelines should be very much as if they were part of the
language.

> > With regards to the maintainability, on the other hand, I can't
> > quite follow you. With local #ifdef, you have to write something
> > like:

> > #if XXX
> > template< class Traits >
> > #else
> > template< class Traits = blah >
> > #endif

> > If you add an additional argument, or change anything else in the
> > given line, you have to modify both lines. That seems like more
> > maintenance overhead to me.

> I consider the overhead negligible because the required change is
> still very local, and the need to apply it to both lines is
> obvious. The alternative still requires a compiler-dependent #ifdef,
> but it is located in a different file, and it requires the maintenance
> programmer to locate that file and open it in order to understand that

> REPEATED_DEFAULT_TEMPLATE_ARGUMENTS(=DefaultTraits)

> evaluates to nothing except for the non-conforming compiler. In
> contrast, the lines between #if and #else, or #else and #endif,
> respectively, are unobscured, immediately intelligible C++.

I agree. The difference is not great, one way or another. But
duplicate code is always more or less a disadvantage. (This doesn't
necessarily mean that alternative solutions might not have greater
disadvantages. I've noticed lately that some people read much more into
what I say that what I meant.)

> Apart, from that, the above was just one example. It is not hard to
> come up with other examples that are not easily solved with a single
> macro.

I'm convinced that such examples exist, and that there are justified
exceptions to my rule of not using #ifdef except as header guards. I'm
also convinced that they are much rarer than most people seem to think.
For the admittedly personal reason that I have not encountered one in
twenty years of programming C/C++, in a wide variety of domains.

I suspect that part of the problem is that most people seem to consider
#ifdef's inevitable, and don't look for alternatives, even when they
exist. If you know about the usual alternatives, have considered them,
and decided that the cure is worse than the disease, apply the
meta-rule, that any rule can be broken.

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Gabriel Dos Reis

unread,
Oct 3, 2002, 10:42:50 AM10/3/02
to

ka...@gabi-soft.de (James Kanze) writes:

[...]

> I don't quite understand that when I make a statement openly concerning
> my own experience ("I don't think I've ever used an #ifdef in production
> code."), people take it as an absolute rule.

Well the way you made your assertion made look and sound absolute.
For the record, this is the statement some of us have been questioning
(I reproduce it here since it is absent from your message I'm replying to):

- One system supports features that the other system lacks. If you

need to target both systems, you don't use these features. *It's as
simple as that*.

(emphasis is mine).

[...]

> My understanding of English is
> that there is a significant difference between "I don't think I've
> ever ..." and "No one must ever ...".

I think your original message doesn't convey the variation you're now
attempting -- I don't claim to be fluent in English (obviously quite
the opposite) but just look at the number of people that were
following-up that statement.

--
Gabriel Dos Reis g...@integrable-solutions.net

James Kanze

unread,
Oct 3, 2002, 2:48:49 PM10/3/02
to
dit...@ix.netcom.com (David Cattarin) wrote in message
news:<30869baf.02100...@posting.google.com>...

> ka...@gabi-soft.de (James Kanze) wrote in message
> news:<d6651fb6.02100...@posting.google.com>...
> > dit...@ix.netcom.com (David Cattarin) wrote in message
> > news:<30869baf.02092...@posting.google.com>...
> > > ka...@gabi-soft.de (James Kanze) wrote in message
> > > news:<d6651fb6.02092...@posting.google.com>...
> > > [snip]
> > > > I don't think I've ever used an #ifdef in production code.
> > > > There are two types of differences between systems:

> > > > - One system supports features that the other system lacks.
> > > > If you need to target both systems, you don't use these
> > > > features. It's as simple as that.

> > > No, it's not. That's the problem with generalizations. What
> > > happens when you *have* to have the feature due to requirements?
> > > Then, on the offending platforms, you have to simulate it. You
> > > may encapulate the problem in a file/class/function, but at some
> > > point, you might very well have to use #ifdef to choose between
> > > the provided feature and the simulated one.

> > Why not use the "simulated" solution everywhere? Why maintain two
> > solutions, when one would be enough?

> Performance is a big reason.

Optimization, in sum. It's true that once the program is tested and
works correctly, if it isn't fast enough, and profiling shows that
there's the hot spot, you do what you have to (carefully documenting the
why's and wherefores, of course), regardless of programming rules.
Optimized code isn't particularly reknown for its readability, but there
are times when you have to.

> > And what are the requirements that are formulated at such
> > implementation detail levels?

> Here's a for instance. I deal mostly with telecom protocols. By
> supporting a particular protocol it forces you to deal with whatever
> data types are contained in the protocol. In some instances, that
> means having to support BCD encoded numbers. There are some systems
> where encoding & decoding strings is provided. On others there is not.
> Why shouldn't I use the (presumably) fast version when it is
> available?

Certainly. This is the sort of thing that is generally encapsulated
behind an interface, though. With machine dependant implementations in
completely different files. (This is, at least, what I did the one time
I had to deal with BCD. With the Intel and the IBM mainframe versions
in assembler, no less.)

> > > > - Both systems support the same functionnality, but in
> > > > different ways. The obvious examples are sockets or
> > > > threads. And the obvious solution is to encapsulate the
> > > > functionality in an object, or if it is really, really
> > > > small, in macros. (I used macros for a while to use the
> > > > new style casts where they were supported, the old style
> > > > otherwise.)

> > > This isn't really true either. Case in point: compiler bugs. I
> > > recently found a bizarre problem with certain HP compilers. The
> > > compiler would fail to compile valid switch code. It claimed that
> > > the break was incorrect. The only way to work around this was to
> > > #ifdef the break and replace it with a goto for the "offending"
> > > lines.

> > Why do you need the #ifdef? Wouldn't the goto work with the other
> > compilers?

> Yes it would, but the point is that the goto was a work around for
> this particular compiler. It was only inserted into the production
> code so that the port to this platform could be completed. Presumably,
> once the compiler is fixed, then the goto can be removed.

But in the meantime, you support two different versions. That's extra
work for everyone involved.

> IMO, the #ifdef acts as better documentation in this case than a
> comment. It emphasizes that the goto is temporary. Once the compiler
> is fixed, this code will be removed.

> But, if the #ifdef wasn't there, someone would probably forget that
> this was a workaround.

Until they had to actually modify the code, and deal with the goto. At
which point, they would see the comments which explained why this horror
was present, find out if it were still necessary, and correct the code
if not.

Until someone has to actually modify the code, the goto doesn't hurt
anyone. And it's there anyway, even if it is compiled with only one
compiler. And what happens if it becomes necessary to change something
in this module before you get the corrected version of the compiler?
How do you ensure that the proper corrections are made in both versions
of the code?

> > > > Can you show me an example of something else? Where you might
> > > > actually want to use an #ifdef in the code. I've never yet
> > > > encountered a case where I would want to, although I think I
> > > > would resist if I did; I can't think of anything which would
> > > > make the code harder to maintain.

> > > How about #pragmas.

> > You win:-). They must be worse than #ifdef's.

> Yes they are! ;)

> > (But I suppose it depends on the #pragma. A pragma that turns
> > certain warnings on or off shouldn't cause any real problems.

> True, but you haven't seen the pages and pages of warnings that are
> generated by the M$ compiler when compiling STL code. There are even
> some clients that requires code to compile with no warnings. Using
> this #pragma is a decent compromise.

Turing off warnings isn't? Or do you mean that the customer requires
you to compile with all warnings on at the global level, but accepts
that you use a pragma to turn them off from within the file? (But I
know, I've had some pretty silly clients too. And since they are the
ones who pay...)

> > A pragma that changes the semantics of legal code will render the
> > program totally unmaintainable, however.)

> True. I only use pragmas to make code work correctly. I've had to
> maintain a lot of production code, so here's another for instance: In
> one piece of code, a developer was using alloca to create variable
> sized arrays on the stack. I had to port it to IBM, where alloca is
> only "enabled" if either a #pragma is present, or a compiler option is
> used. I suggested to the developer to use the #pragma (#ifdef'd for
> IBM) in only that file.

I think I'd have gone for the global option (or modified the code to not
use alloca), but since I don't know the situation in all of its details
(including the non-technical aspects), I can't say for sure.

> > > You might want to #ifdef these to avoid confusing a compiler on a
> > > different platform. For people doing windows' programming, I'm
> > > sure the following construct is familiar:

> > > #ifdef WIN32
> > > # pragma warning ( disable : 4786 ) // warning for truncated
> > > debugging info
> > > #endif

> > > This avoids disabling the wrong warning for a different compiler.

> > Well, it seems strange to me that such a silly warning would be on
> > in the first place (or even exist), but who knows. But surely want
> > to disable it globally, and the command line is the place for that.

> Fair enough, but I don't have control over the company's make system.
> Every time I've made a suggestion, there has been days/weeks of
> discussion/battle over whether or not my suggestion should be
> implemented.

Understood. Thus, it's not that conditional compilation is good. It's
just that politically, you can't use the better solutions. (Note that I
don't mean this critically. In real life, the political aspects are
always present, and we have to live with them. In well managed
projects, they even have a positive effect on your productivity. But I
think every programmer has to realize that he isn't alone on the
project.)

> > And if only a pragm will do:

> > #include "SystemPragmas.hh"

> > with a version of the header for each system, in a system dependant
> > directory specified by a -I option in the command line.

> Fair enough. That is a reasonable suggestion, but I haven't had a
> chance to work out what I'd put there.

Part of the message of Spencer and Collyer is that portability is a
design issue, and working out what has to go into such a file isn't
trivial, but it is necessary if you want to be portable and keep the
code maintainable.

> > Note that I'm not really trying to be dogmatic here, but to
> > indicate that other solutions exist, and that except in rare cases,
> > they will be preferable.

> I do like seeing different viewpoints in these discussions. But, I
> think even you recognize that there are cases, maybe not so rare, whre
> #ifdef is useful.

My first statement was that I don't think I've ever used one in
production code. That suggests to me that at least in the type of work
I do, the need for one must be pretty rare. That certainly doesn't mean
that it could never happen.

> > > How about compilers with different levels of standards
> > > compliance. I use the following code to get around problems with
> > > ostream formatting.
> [snip]

> > At present, my application level code only includes my own IO
> > headers: "iostream.hh", "istream.hh", etc. Again, these files
> > exist in different versions, in different directories, and the
> > version used is selected by a -I option in the command line. The
> > file "ios.hh" is either:

> We have a development policy that forbids the use of extensions like
> ".hh".

And requires .h? I suppose that you could always call them
"myiostream.h", etc.

> > #include <ios>
> > namespace Gabi {
> > typedef GB_iostd::ios_base::fmtflags FmtFlags ;
> > static int const eof = GB_iostd::char_traits<char>::eof() ;
> > }

> > or:

> > #include <iostream.h>
> > namespace Gabi {
> > typedef long FmtFlags ;
> > static int const eof = EOF ;
> > }

> I do like that, but it might not be so easy to get others to use the
> same approach.

That's the real problem. Because the one thing you don't want is for
everyone to use a different approach.

> > I would consider what you have written as a perfect example as to
> > why #ifdef is not appropriate to production code. You can't really
> > tell me that this is maintainable.

> It's been in production code for 3 years and has been ported to 9
> platforms. It works just fine, even if it is ugly. I'll admit that I
> chose the expedient solution.

Sometimes we have to. The important thing is to realize that that is
what we have done, document it, and fix it to use the more robust
solution at the first possible occasion.

> Speaking of production code, have you taken a look at any STL
> implementations? I haven't seen one that doesn't liberally use
> #ifdefs.

Have you seen one that you would use as a model of how you want code to
look?

> [snip]
> > > I feel that #ifdef (and #if) have valid places in production code.

> > Maybe, but I've yet to see one.

> How about include guards?

The exception is so obvious I forgot to mention it. The rule is that
include guards are always done with an #ifndef. And with a name derived
from the file name in a manner specified by the project (or some higher
authority at the client site), and consistent in all of the files.

> Anyway, maybe I can convince you that there are *some* uses. ;)

The include guards, at any rate:-). And I wouldn't exclude the
possibility that others exist.

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

unread,
Oct 3, 2002, 2:50:59 PM10/3/02
to
Gabriel Dos Reis <g...@integrable-solutions.net> wrote in message
news:<m37kh0x...@uniton.integrable-solutions.net>...
> ka...@gabi-soft.de (James Kanze) writes:

> [...]

> > I don't quite understand that when I make a statement openly
> > concerning my own experience ("I don't think I've ever used an
> > #ifdef in production code."), people take it as an absolute rule.

> Well the way you made your assertion made look and sound absolute.

"I don't think I've ever used an #ifdef in prodution code" looks and
sounds absolute?

> For the record, this is the statement some of us have been questioning
> (I reproduce it here since it is absent from your message I'm replying
> to):

> - One system supports features that the other system lacks. If you
> need to target both systems, you don't use these features. *It's as
> simple as that*.

> (emphasis is mine).

This statement was in a subsection treating one particular case where
I've seen conditional compilation used, and where I don't think it is
appropriate. And I'll admit that I hadn't considered the case of
general purpose libraries, which may be an exception even in this case.

> [...]

> > My understanding of English is
> > that there is a significant difference between "I don't think I've
> > ever ..." and "No one must ever ...".

> I think your original message doesn't convey the variation you're now
> attempting -- I don't claim to be fluent in English (obviously quite
> the opposite) but just look at the number of people that were
> following-up that statement.

And look at what they are saying. At least two have responding
supporting my position. For the most part, the others don't seem to be
really critical with regards to the idea, but are interested in the
techniques used to implement it. (I don't know whether it is a
coïncidence or not, but most of the participants in the thread are NOT
native English speakers. Maybe my English is so deformed that only a
European can understand it, and then not the way I meant. And for the
native English speakers who aren't quite sure what I am talking about:
there is a European English dialect, distinct from either British or
American usage, used when French, Germans and Italians have to
communicate with one another.)

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

unread,
Oct 3, 2002, 2:52:13 PM10/3/02
to
Gerhard Menzl <gerhar...@sea.ericsson.se> wrote in message
news:<3D9AAC89...@sea.ericsson.se>...

> James Kanze wrote in reply to an example involving compiler
> differences with regard to default template arguments:

> > The solution in application code is simple: don't use default
> > template arguments.

> and:

> > Forgo default template arguments altogether. IMHO, the answer here
> > is simple. New features are a potential source of problems. Don't
> > use them until you know they work everywhere.

> I had an inkling that something along these lines was going to appear
> in your reply. :-) And as with most of the rules which to proclaim you
> have a reputation for, I agree in theory and in principle. The same
> compiler that implements default template arguments incorrectly also
> has shaky support for exceptions and namespaces, so we don't use them,
> even though that means that I cannot apply most of what is discussed
> here or in Herb Sutter's books in my daily work. Life can be tough.

Don't tell me.

Note that sometimes, it can even be tougher than it has to be. Most of
the places I see are still using g++ 2.95.2 (no std::stringstream,
even), where as in every case, g++ 3.1 is available, much more up to
date, and sufficiently robust.

> On the other hand, if you were to obey your rule rigorously and
> without exceptions (pun not intended), you could easily end up
> forgoing virtually all C++ features that are not in C.

Or even sticking with K&R C:-).

This is a real problem. You start by not using certain features because
they aren't mature enough. And you continue not using them because
everyone is used to the work-arounds, etc. Or you have to remain
compatible with some existing code. I've currently got a large body of
code which uses a home-build vector class. Which is apparent in the
interfaces, which means that changing it will require a change in the
interfaces. And all of the users have other priorities, and we'll never
find a moment when all can rework their code at the same time.

It's a similar problem with g++. Generally, if the company is sticking
with 2.95.2, it's because it works. And since no one bothered to stick
in the std:: that were needed (except me, and I probably forgot a few as
well), the code doesn't compile with 3.1. And even though the
corrections are easy to find (a compiler error) and fix, it seems that
we've always got a release to do, and it will have to wait until after.

For the applications I currently work on, we only have to support the
mainline Unix (the last two, only Solaris, in fact) and Windows NT. For
these machines, if we standardize on VC++ 7.0, and the latest versions
of the Unix vendors compiler OR g++ 3.1 (not really an option here,
because we are multithreaded, but generally a possibility), there is a
lot we could do.

But there are only so many battles that I can fight. And in the end,
convincing them that checking the return codes of the system calls might
be a good idea is more important than convincing them to upgrade
compilers.

> Or even more than that - said compiler was found to have problems
> implementing static locals correctly, for example. You also have to
> take into account that compiler incompatibilities often remain
> undetected before large parts of code have been written.

I've experienced this in Java:-). One week before we went live.

> If you claim that this is impossible as long as a proper development
> process is followed (as I could well imagine you saying :-) ),

One of the most important things in a proper development process is to
recognize that no error is impossible. (What is impossible in a proper
development process is that the bosses haven't planned time for the
unexpected errors. But I have enough experience to recognize that very
few develpment processes are that good.)

> consider the case of porting an existing application to a new platform
> that requires an older compiler. Would you advocate rewriting existing
> code for the sake of an aberrant newcomer? Even if you know its
> EDG-based successor is just around the corner? I would think that the
> cost of bridging the compatibility gap with an #ifdef is far
> outweighed by the cost of dumbing down (and recompiling, and
> regression-testing) existing and working code. It is simply not
> possible always to determine in advance which features are going to
> work everywhere.

That's a hard question.

Spencer and Collyer recommend the rewrite. On the grounds that if you
encounter the problem one place, you'll probably encounter it again
somewhere else. On the other hand, at the time they were writing, there
was no real Unix standard, at least not one which covered everything
they used (sockets, etc.). Whereas we know (I hope) what the future
will bring in C++ compilers.

> > I'll admit that this is one of the limit cases, however, since both
> > compilers offer the functionality, just in different forms (and the
> > user code doesn't see the difference). Still, I suspect that if
> > you need to support two different variants of a new feature, the
> > need will arise to support a compiler which doesn't support the
> > feature at all, and you'll have to do without anyway.

> This argument, when taken to the extreme, would prohibit the use of
> C++ in production code altogether, particularly in the embedded
> systems domain. Not really an option when your job is to maintain and
> enhance an existing C++ application.

That's not really true, but it does limit your options. I recently had
to remove everything that used member templates in my reference counted
pointer class, because they weren't available on one of our target
compilers.

What I can see no point in, of course, is maintaining two versions of
the class. But then, the code is part of the application; there are no
users who don't suffer the same constraints as our application does.

> In addition, this is not just about missing language features. In
> practice, #ifdefs can be a reasonable and cost-effective way around
> compiler bugs. Compilers usually don't come with a big, red sticker
> "Warning! Cannot handle anything resembling template<class T> ...", so
> this is nothing you can really anticipate.

> > An STL implementation is what I would call a general library. As I
> > said above, I'm less certain about this, because I have no real
> > experience with it. At the very least, I, as a user, would hate to
> > be deprived of the template member functions because some of the
> > library users (but not me) have to compile with a compiler which
> > doesn't support member templates.

> My job mainly involves writing general libraries for the application
> developers (if not as general as the STL), so maybe this explains our
> different views.

And of course, some of your users aren't burdened by out of date
compilers. I can understand wanting to offer them the possibilities of
the new features.

I would still look for solutions other than conditional compilation.
But it is clear that my experience ("I've never needed ...") isn't very
applicable. It's quite possible that I would find cases where the
alternative solutions seemed worse. I don't know.

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

unread,
Oct 3, 2002, 2:53:07 PM10/3/02
to
Gennaro Prota <gennar...@yahoo.com> wrote in message
news:<317mpukljkisa2e4e...@4ax.com>...

> On 1 Oct 2002 13:08:32 -0400, ka...@gabi-soft.de (James Kanze) wrote:

> >Gabriel Dos Reis <g...@soliton.integrable-solutions.net> wrote
> >> Gennaro Prota <gennar...@yahoo.com> writes:

> >> [...]

> >> | I suppose in such a case Mr. Kanze would simply include the
> >> | header with the definition and give up using forward
> >> | declarations. But that's a bad service to people who have
> >> | serious compilers: they have to pay for a defect of someone
> >> | else.

> >> Maybe in such case, Mr. Kanze won't support more than one C++
> >> implementation ;-)

> >More likely, I'd say that default template arguments are a feature
> >that isn't ripe enough for production code, and not use them.

> Over-generalized opinion, IMHO.

With a "more likely" qualifier? And followed immediately by an or, and
other options?

The "best" solution, supposing such a thing even exists, depends on a
lot of issues, most of which we don't know here. Someone put an answer
in my mouth that is about as far as possible from what I would really
say. It is far more likely that I would suggest one of the solutions I
list. It is, however, also possible that in certain conditions I would
recommend not supporting more than one C++ implementation, or even that
I would say that his case is one of those rare exceptions which confirm
the rule.

> >Or adopt a
> >solution along the lines of what Jean-Marc suggested.

> Ok for me. As long as you accept/admit that you still have a #if/#else
> for the definition of the macro.

Why? Normally, such macros are defined in a machine/system/compiler
dependant include file. There is one such file per
machine/system/compiler combination. Each of the files is in a separate
directory. And the directory is specified by means of a -I option on
the command line.

At least, that's the way I've always done it.

It's a shame my site is down, or I could point you to examples. And
FWIW: in the code at my site, there *were* #ifdef. But as the
introductory pages made clear, the code at the site was NOT production
code, but experiments. At one point, for example, I wanted to
experiment with what could be done with member templates, even though
some of the code was being used with a compiler which didn't support
member templates. Bingo, a #ifdef. To experiment, however, and not in
production code. (Actually, the current state of the code is that it
probably won't compile with anything but g++ 3.1. So when I find the
time, I'll go back and remove all of the pretexts of portability:-).)

> >Or even decide that the situation justified an exception to the
> >rule: I'm a pragmatic person.

> Thanks :-)

> >However, as I have pointed out, my original statement concerned my
> >actual experience. I have no experience in general purpose
> >libraries, which must be delivered to many different customers. So
> >maybe my decision would be different in such a case.

> >I don't quite understand that when I make a statement openly
> >concerning my own experience ("I don't think I've ever used an
> >#ifdef in production code."), people take it as an absolute rule.

> I think that's a drawback of being a well-known expert. Had I said the
> same thing, do you think it would have arisen all this dust? :-)

Well, if I'm so well known, then it should be known that I'm an
applications programmer, extremely concerned about program quality
(because a number of my applications turn 24 hours a day, 7 days a
week), AND concerned about portability and localization. So 1) it
should be clear that I'd rather have robust and maintainable code than
push the envelope with the lastest features, and 2) any time I refer to
my experience, it excludes a certain number of things.

I generally try to be careful to distinguish between my personal
experience ("I don't think I've ever ...") and concrete facts ("In
§x.y.z, it says "..."). I certainly hope that I've not given the
impression that #ifdef is somehow illegal. I do hope that I've given
the impression that I think that it is something to be avoided, and that
I think that it can be avoided much more than it is.

> >I think that #ifdef are something to avoid if at all possible. But
> >like all rules, that is subject to the meta-rule that it can be
> >violated if the circumstances justify. In this case, all I said was
> >that in my own experience, I've never encountered a case where the
> >circumstances justified it. As a statement, it has some
> >informational value, because I have a fair amount of experience, in
> >both commercial and industrial domaines. But it is hardly an
> >absolute, since there are other domains (general purpose libraries,
> >game software, numerics) in which I've no experience; since even in
> >the domains I have experience, there might be particular cases that
> >I have experienced; and since I rather nuanced the statement
> >anywhere "I don't think I've ever ...". My understanding of English
> >is that there is a significant difference between "I don't think
> >I've ever ..." and "No one must ever ...".

> Ok. I see some grudge in your words which is probably due to my phrase
> "I suppose Mr. Kanze...";

Not just your words. In general, I find it bothersome when people make
suppositions concerning what I would do when they know very well that
those suppositions are false. (Let's face it: as you say, I'm not
exactly unknown, and pragmatism IS a characteristic of many of my
postings. I find a solution which works, even if it isn't always 100%
pure.)

> actually that phrase was meant to say that I wasn't sure about what
> you would have done in such a case, and that I was just guessing. No
> intent to be disrespectful on my part, as I tried to make clear from
> that 'Mr.' in front of your name (intended as a sign of respect).

But it reads funny in a newsgroup:-).

> However I'm far from sure that I expressed in a way that achieved my
> goal, it's very likely that to a native speaker the phrase gives a
> completely different impression.

I don't know, but the problem isn't any one posting. It is several
speculating that I would, in some way, renounce supporting someone, or
give up some functionality. It is also several acting as if I had made
a categorical statement to the effect that one must NEVER use an #ifdef,
whereas I very explicitly refered to my personal experience.

> {The trouble is that an insertion of an honorific when one would not
> normally use it can be taken with the exact opposite meaning. English is
> a confusing language, its close similarity with American makes it more
> so:-)
> -mod/fwg}

Quite. The Mr. in Gennaro's posting is rather vague -- one doesn't
really know how to take it, so one assumes the best. The Mr. in
Gabriel's response to it, however, sounds almost mocking to me. But
language is a funny thing: I specifically speak of my personal
experience, and people think I'm expounding an absolute rule. And when
I reread some of my own postings, I wonder if one or two of the
questions might be interpreted mockingly.

> Now for a general remark: guidelines are "means", not ends. Take e.g.
> the "test for features, not for systems".

That is exactly what I have been saying.

Generally speaking, #ifdef's don't help maintainability or readability.
But we have to deal with variations in systems. So we have to do
something. Generally speaking, #ifdef's are not good, but if all of the
alternatives are worse?

The point of citing my experience was to highlight the fact that it is
probably a fairly rare case where the alternatives are worse.

> Its reason to exist is in the fact that (among other things) the same
> system may be upgraded/fixed in the future making your implication "if
> this is system XYZ then feature KXY is missing" suddenly become
> incorrect.

Your code won't suddenly stop working. Some of the programs I use were
written 15 or more years ago. Some of them are still in K&R C, because
I've not had the occasion to upgrade them, and they work. Others, just
as old, now use the STL more or less intensively, because I recently
added a feature or two, and took advantage of the occasion to upgrade
them generally.

This doesn't just affect new language features. My point of view
concerning what is good programming has evolved, too, and even if for
some reason, the program still had to be in K&R C, I'd "upgrade" it to
my more recent coding standards.

But I don't think I'm following you. What does this have to do with
using #ifdef? Or using a feature that isn't supported in one of the
compilers you have to target.

> In other words: it's an issue of maintainance/future validity of the
> code. Of what we could call the two *parts* of a guideline, i.e. the
> "mean" and the "end", the first one is what the common language calls
> "guideline", however that's IMHO the less important part. The most
> important is the end. And, as programmers, we must break the guideline
> if there are better means to achieve the same end (for some
> definition/opinion of "better" - that's the true problem).

There are always cases where you have to violate the guideline. The
general rule has always been that it is permitted, provided you provide
comments to justify the reason, and these comments convince the code
reviewers (your peers).

> Now, let's consider this default template arguments example:

> // in x_fwd.hpp
> template <class T = int, class U = std::allocator<T> > class X;

> // in x.hpp
> #if .... // buggy compiler
> template <class T = int, class U = std::allocator<T> >
> #else
> template <class T, class U>

> class X { /* ... */ };

> In this case we could also choose to not use default arguments (which
> I dislike for the reasons I said elsewhere),

In the case of the allocator argument, I'd drop the argument if there
was even one compiler that didn't support default arguments. But again,
this is just my experience: I've never found a use for it. Requiring
everyone to specify the argument just so the rare case might potentially
be able to use it seems wrong to me.

But I doubt that the fact that your default argument is an allocator is
really your point.

> or hiding that #if/#else behind a macro:

> # if .... // buggy compiler
> # define DEF_ARGS_IN_THE_DEFINITION class T = int, class U =
> std::allocator<T>
> # else
> # define DEF_ARGS_IN_THE_DEFINITION class T, class U
> # endif

> That's ok for me, as long as nobody complaints about the use of a
> macro in its own (macros are evil... macros don't respect scope...
> etc...).

Macros are, in fact, a meta-language to generate C++. Which seems
appropriate here. The fact that the guidelines don't allow macros for
defining manifest constants, or for simulating inline functions, isn't
being violated.

On the other hand, I'd never write anything like you just wrote.
Jean-Marc gave one solution that I use fairly frequently, in which he
defined a macro:

#define DEFAULT_TEMPLATE_ARG( arg ) = arg
or
#define DEFAULT_TEMPLATE_ARG( arg )

You write:

template< typename T,
typename U DEFAULT_TEMPLATE_ARG( std::allocator) >

Not really pretty, but when all of your compilers are finally up to
date, with a name like that, it's pretty easy to do a global find and
replace.

(Because of the funny use and scoping, this is one case where the name
must stand out -- I use all caps. Also, I would normally define a
prefix in the coding guidelines for all names of this type, on one hand
to reduce the risk of conflicts, and on the other to make it immediately
obvious to anyone who is familiar with the coding guidelines why this
particular macro is there, and where he should look for its definition.)

> As an as much questionable device you could decide to #undef the macro
> at the end of x.hpp.

The macro solution is only viable if the macro is defined in a separate
header. And potentially used everywhere templates with default
parameters are involved. So no #undef.

> Note also that you can choose to #define the macro in x.hpp (so that
> it remains 'local' to that file), but if you do so then someone could
> tell you that there's the problem of keeping it synchronous to
> x_fwd.hpp. If you want to have one place where the default arguments
> are specified without having a macro in x_fwd.hpp that you can't
> #undef at the end of the same file then you have probably to use some
> helper template, because the second default depends on the first
> argument:

There are two separate issues. The orginal problem that was given was
that all of the compilers supported default arguments to templates, but
that one required the arguments in every template declaration, whereas
the others, in conformance with the standard, forbid the argument in
more than one of the template declarations.

My immediate reaction to that is that if compilers vary that much in
their implementation of the feature, the feature is probably not mature,
and not ripe enough to be used in production code. But this is only a
very general guideline, and subject to a lot of exceptions. A macro
FOLLOWUP_DEFAULT_TEMPLATE_ARG, along the lines of the above, handles
this in what is in my opinion an acceptable way as well. (Although as
you say, anytime you have to repeat the same information, you are
creating a maintenance headache. The fact that one compiler requires
that you repeat this information is another indication that perhaps you
should do without default template arguments for the moment.)

[example cut...]

> Note how I'm pointing out the fact that when you work in team you have
> to satisfy others too.

Quite. That's what coding guidelines and code review is for.

Hopefully, you will have discussed the problem and agreed on a standard
solution for it before you encounter it. In that case, you use the
standard solution. Unless there are really overwhelming reasons to
deviate. The macro based solution *doesn't* work if you invent it on
your own, and use it without telling anyone. Do that, and you WILL have
the maintainance problem that Gerhard Menzl is worried about.

> Actually the reason why I have used a "direct"
> #if/#else for dynamic_bitset is the sort of fear that everybody have
> for macros. They will tell me, I thought, that macros are best
> avoided.

And conditional compilation is best avoided. And complex code is best
avoided. And wouldn't it be nice if nothing we did were every more
complex than "hello, world". Macros ARE best avoided. But you have a
problem to be solved, and you have a limited number of possible
solutions. None of which are particularly nice.

> To be honest I have used a macro anyway, i.e. the highly readable (;-)
> BOOST_WORKAROUND_REPEAT_DEFAULT_TEMPLATE_ARGUMENTS but that's for the
> good reason, we all know (As an aside I think that the rule that long
> names are *always* clearer is quite stupid too. But let us not put too
> many irons in the fire).

Above all, it works because 1) there are other macros with names like
BOOST_WORKAROUND_WHATEVER_ELSE_DOESN_T_WORK, 2) this is the standard
way of handling portability issues in Boost -- anyone reading Boost code
recognizes immediately what is taking place, and 3) the macros are
defined in a separate, centrally maintained file -- when porting to a
new system, someone creates a new version of this file, and (if you are
very, very lucky) all of the code just magically works with the new
system.

> IMHO, that (guessed but, you know, possible) objection means confusing
> the mean for the goal. However one has to come to a compromise with
> the opinion of others of course.

> Granted, as you say there's a meta-rule that says a rule can be broken
> if you can justify the reasons for breaking; but everything depends on
> what other things about "justifying". I think for instance that main()
> should have a return statement, and there's no reason for it to be a
> special case.

I do to. But not to the point of inserting a return statement if the
local consensus says not to.

> Also I think that prohibiting (void*)0 to be a null pointer constant
> is a silly and gratuitous incompatibility with C, and that the
> "rationale" often quoted for not allowing forward declarations of
> enums is silly.

I do to, but in this case, the consensus is actually formalized in the
standard. I use NULL (unless the client coding conventions insist
otherwise), but in no case would I even think of using (void*)0.

> However there are top-level experts that would kill me for these
> assertions.

If your assertion is that you think X is better, in these cases, anyone
who would kill you for it isn't an expert. An expert might have other
preferences (I think that Stroustrup prefers 0 to NULL), but any expert
will recognize that there is a lot of room for different opinions with
regards to these two points.

> As you see, it's a matter of opinions (despite the fact that we try to
> make everything appear as pure, objective, incontrovertible
> logic). I'm sure there's people around that is convinced of some
> incontestable reason why #ifndef should be used for include guards
> instead of #if !defined, and maybe that's one of the issues one can
> arise to beat the record of the longest c.l.c++.m thread too :-)

There's no technical reason, or the technical reasons aren't
overwhelming. But there may be non-technical reasons. In all of the
places I've worked, everyone has always used #ifndef for the include
guides. IMHO, it would definitely be an error to be different with
regards to this. Not for any technical reason, but differences tend to
be remarked. If there's a serious technical problem which requires a
different answer, this is a good thing. For include guards, it is
definitly not a good thing.

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Gerhard Menzl

unread,
Oct 3, 2002, 3:25:09 PM10/3/02
to
James Kanze wrote:

> I'm convinced that such examples exist, and that there are justified
> exceptions to my rule of not using #ifdef except as header guards.
> I'm also convinced that they are much rarer than most people seem to
> think. For the admittedly personal reason that I have not encountered
> one in twenty years of programming C/C++, in a wide variety of
> domains.

Not even

#ifdef __cplusplus
extern "C" {
#endif

?

> I suspect that part of the problem is that most people seem to
> consider #ifdef's inevitable, and don't look for alternatives, even
> when they exist. If you know about the usual alternatives, have
> considered them, and decided that the cure is worse than the disease,
> apply the meta-rule, that any rule can be broken.

I think we have reached agreement here.

Gerhard Menzl

Gerhard Menzl

unread,
Oct 4, 2002, 9:30:01 AM10/4/02
to
Jean-Marc Bourguet wrote:

> I prefer having all my platform dependend stuff in the same place (or
> at least in some restricted set of places) than having them scattered
> all along the code. Knowing that to handle all known compiler and
> system dependancies I should have only to modify the "sysindep"
> library and two makefile fragments which are included in the
> makefiles is a good starting point. Now there will be surprises, but
> they will be surprises and not something which should have been
> expected.

This is undisputed. I have never advocated scattering platform-specific
#ifdefs all around the code. My example contained a *language
feature-specific* test (does or does not support this feature
correctly). The platform-specific tests upon which the language-feature
specific tests depend would (and are usually) be kept in a central
place.

> It is always a matter of trade-off. My reaction was to the statement
> "it is not possible to handle this case without #ifdef". I showed a
> way that I'd prefer to #ifdef in the kind of programs I've worked on.

I have never made a statement to that effect. What I claimed is that in
the presented example an #ifdef is the lesser evil.



> Even if a test occured only in one place, it could be usefull to put
> it at the place were other such tests are made, because that's where
> people will look for the test. Consistency with existing practice is
> an important factor. If in an project such matters are currently
> handled with #ifdef, I'll use them and nothing else.

The test is always there. With an #ifdef, it's explicit. A macro
obscures it, and keeping two versions of the same file hides it
completely. Depending on the nature of the condition you are testing,
any of the above solutions may be appropriate. You have to balance
abstraction and flexibility against locality and visibility.



> BTW, these are not the only possibilities. Standardizing on one
> compiler available on the supported platform (for example g++ or
> comeau) is another for solving the issue at hand.

Nobody (at least nobody of sound mind) will voluntarily target as many
compilers as possible just for the fun of it. Being able to choose
compilers freely is a luxury few people can enjoy. You ususally resort
to #ifdefs when you have to deal with incompatible implementations, and
you cannot do anything to change it in the short term.

Gerhard Menzl

James Kanze

unread,
Oct 4, 2002, 9:43:19 AM10/4/02
to
Gerhard Menzl <gerhar...@sea.ericsson.se> wrote in message
news:<3D9C580A...@sea.ericsson.se>...
> James Kanze wrote:

> > I'm convinced that such examples exist, and that there are justified
> > exceptions to my rule of not using #ifdef except as header guards.
> > I'm also convinced that they are much rarer than most people seem to
> > think. For the admittedly personal reason that I have not
> > encountered one in twenty years of programming C/C++, in a wide
> > variety of domains.

> Not even

> #ifdef __cplusplus
> extern "C" {
> #endif

> ?

No. But I'll admit that this is probably because I moved from C++ to C
as a result of a job change, and never had to work in an environment
where both languages were present. I suspect that this is as much of a
consecreated idiom as the include guards.

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Gerhard Menzl

unread,
Oct 4, 2002, 3:26:37 PM10/4/02
to
James Kanze wrote:

> Gerhard Menzl <gerhar...@sea.ericsson.se> wrote in message
> news:<3D9AAC89...@sea.ericsson.se>...
> > consider the case of porting an existing application to a new
platform
> > that requires an older compiler. Would you advocate rewriting
existing
> > code for the sake of an aberrant newcomer? Even if you know its
> > EDG-based successor is just around the corner? I would think that
the
> > cost of bridging the compatibility gap with an #ifdef is far
> > outweighed by the cost of dumbing down (and recompiling, and
> > regression-testing) existing and working code. It is simply not
> > possible always to determine in advance which features are going to
> > work everywhere.
>
> That's a hard question.
>
> Spencer and Collyer recommend the rewrite. On the grounds that if you
> encounter the problem one place, you'll probably encounter it again
> somewhere else. On the other hand, at the time they were writing,
there
> was no real Unix standard, at least not one which covered everything
> they used (sockets, etc.). Whereas we know (I hope) what the future
> will bring in C++ compilers.

I don't know the authors, but this sounds suspiciously like a
recommendation from within an ivory tower. My manager would ask me if
I'm nuts if I were to suggest rewriting half of the application for the
sake of avoiding an #ifdef.

Gerhard Menzl

Thomas Mang

unread,
Oct 4, 2002, 3:28:55 PM10/4/02
to
ka...@gabi-soft.de (James Kanze) wrote in message
news:<d6651fb6.02100...@posting.google.com>...
> a980...@unet.univie.ac.at (Thomas Mang) wrote in message
> news:<c9ab3170.0210...@posting.google.com>...
> > ka...@gabi-soft.de (James Kanze) wrote in message
> > news:<d6651fb6.02100...@posting.google.com>...
>
> > > Sure you can. Today, at least. You can't use member templates,
> > > and there is a lot of other things you can't do with templates,
but
> > > basic, straightforeward use of templates works pretty much
> > > everywhere today.
>
> > Doesn't this implicitly encourage compiler writers NOT to become
> > standard - conforming?
>
> I don't think so. Not directly, at any rate. I doubt many compiler
> writers ever look at my code, to see which features I'm actually
using,
> and which ones I'm not.

Compiler writers don't look at my code too. Certainly, no compiler
writer will ever care about my code, wether I use #ifdef ... and so
on. But they have an idea about what programmers are doing in real
world. And that is, IMHO, unfortunately to rely too much on ancient,
non-standard features.


> Of course, just because you don't use a feature yet, you shouldn't
stop
> asking for it. Here, and anywhere else you can make yourself heard.
>
> And there is an indirect risk. If instead of asking you, your bosses
> look at what you are currently using to determine what to look for in
> the next compiler, they might inform the compiler implementors that
the
> new features aren't important.

I think that's why we have a standard - to tell compiler writers what
to implement. But as it seems, many do not get it even right to
implement basic features of the standard, such as <iostream>. Instead,
they develop optimizations for the newest processor instructions

>
> > I think many managers of compiler software will be tempted to say
> > something like "nobody uses it, so don't spend money on developing
> > it".
>
> Nobody used Windows when all we had was MS-DOS. Nobody used Windows
> 2000 when all we had was Windows 98. Etc., etc.

You missed the point here.
I was talking about non-common used, but nevertheless standardized
features, which are requirements for a fully standard conforming
implementation. Developing something new(which certainly will not have
been used at this point) is optional for every compiler writer,
implementing the standard should be a must, and should have
precedence.

>
> My impression is that the vendors (or at least some vendors) are
> constantly looking for something new to implement, if only to sell you
a
> new version.

I agree.

>
> > Today compilers offer really nifty optimizations, and other stuff
they
> > don't have to develop (according to the standard, such as more
> > keywords....).
>
> A lot of compilers offer really nifty optimizations because their
> customers want them:-).

Yes. But is it true that, if we'd ask programmers to elect, more would
prefer the newest nifty optimization for a processor used by a
minority of customers, which will anyway never be used because we
compiler code for a broader chipset, over standard features?
Maybe I am living in a dream world. But for me(in a programmer's point
of view), all optimizations but of the very basic ones(e.g. return
value optimizations) should be implemented AFTER the standard has been
implemented.

>
> > I'd prefer compilers which FIRST implement the standard features,
and
> > THEN improve their code further.(After all, I do not consider speed
a
> > critical factor in most apps).
>
> I agree, but the guy next door who is working on a CPU intensive
> application which only uses double[] probably doesn't.

If that's the case, it is best to program in native instruction code.
Where is the guarantee that the compiler will really optimize the
code? Or even more unlikely, that it will produce the fastest code
possible?

>
> Historically, I fear that the usual order of priorities has been:
>
> speed
> new features
> robustness

I agree with this too. (including the 'fear').

>
> As far as I'm concerned, that is 100% backwards. But I don't think
not
> using a feature because it isn't there is a reason for this.
>
> > And everything that releases pressure on compiler manufacturers to
> > implement a standard conforming implementation is, for me, a walk
in
> > the wrong direction.
>
> If you really think that maintaining two versions of the same code
> (which the compiler manufacturer will never see) will somehow increase
> the chance of your compilers becoming standards conform, go for it.
> (And I'm not being 100% cynical -- I can imagine environments where
> showing a boss a lot of code loaded with #ifdef, and explaining to him
> that you wouldn't need all this if compiler X would get their shit in
> order, might be the only way to get your company to apply presure on
the
> vendor. Until now, however, I guess I've been lucky, and all my
bosses
> have asked me what we needed, and believed my answer without looking
at
> the code.)

I do not believe (nor even dream) that _MY_ code will have pressure on
compiler writers. It's the world of programmers which can make
pressure. Certainly, requiring more efficient code (by means of speed)
is a pressure too, but IMHO the wrong one.

The next round of standardization is ahead. But what will this be good
for, when most implementations (all ??) haven't implemented the
1997/98 standard yet, because there focus is on code optimization, GUI
widgets, debuggers and all the rest?
I can't see a reason in having a theoretical standard in the ivory
tower used nowhere, because it works nowhere. But this is the status
we currently have.

Don't misunderstand me, I am on the side of the standard. I hope that
in the near future compilers will become standard conforming. That's
why I use the #ifdef: Whenever I can implement some functionality in
an easy (straightforward) way which compiles on every system, I
certainly use this. I do not write fancy code which's only goal is to
be unreadable / understandable by everyone not being 100% familiar
with all cute little features of C++.
But occasionally, there isn't this simple way, and I have to use more
advanced features of C++. Than I use #ifdef for a version that
compiles right now, and one that will (hopefully) compile soon.

But as it seems, programmers are running in different directions:
Some propose to use standard-features whenever possible. Take a look
at std::vector. Many suggest to prefer std::vector over allocated
arrays using ::operator new. We can usually do this, because
std::vector can be quite easily implemented.
But what about the other features?
Some programmers don't use them, because they are not implemented on
most systems. Then I ask, why don't we throw them out of the standard,
when more or less no implementation seems to support it?
After all, not compiler writers depend on the standard, we depend on
compiler writers. Either we try to hang on to the standard (meaning to
write <iostream> whenever possible, and using "iostream.h" only when
not, and throw this out as soon as possible), or we stop standardizing
and everybody is satisfied with what the compiler provides.

But it was the intent of standardization to have a common layer
implemented by all compilers. If we don't rely on this, we can equally
good stop every standardization process.


BTW, this is an idiom found everywhere in life:
Have the profit right now, don't care about the future. Others will
have to deal with it, so it's their problem.

For me, this is clearly the wrong way.


And additionally, the #ifdef's are also a good way to find out which
compiler is more standard conforming. Whenever I can, I select the
compiler which compiles my code with the least ____xxx_BUG #defined.

best regards,

Thomas

David Cattarin

unread,
Oct 4, 2002, 6:08:53 PM10/4/02
to
ka...@gabi-soft.de (James Kanze) wrote in message
news:<d6651fb6.02100...@posting.google.com>...
> dit...@ix.netcom.com (David Cattarin) wrote in message
> news:<30869baf.02100...@posting.google.com>...
[snip]

Well, after all that, I can certainly agree that I could do better at
avoiding #ifdef.

> > Speaking of production code, have you taken a look at any STL
> > implementations? I haven't seen one that doesn't liberally use
> > #ifdefs.
>
> Have you seen one that you would use as a model of how you want code
to
> look?

LOL. No, of course not. But I've worked on enough system tools and
libraries that I can appreciate the problem. Looking at the xerces
library, I can see that they take the approach of using different
directories for system dependent code. I'll keep it in mind in the
future.

[snip]


> > Anyway, maybe I can convince you that there are *some* uses. ;)
>
> The include guards, at any rate:-). And I wouldn't exclude the
> possibility that others exist.

Aside from compiler bugs and include guards, there is at least one
other case where I think I'd still prefer #ifdefs, and that is for
dealing with non-standard C++ compilers. It would be great if I could
just compile my "standard" code on all compilers, but then there is
reality. Encapsulating the problem code into other files is a good
solution, but it galls me that I'd have to do that let alone #ifdef a
work-around. Oh well.

I guess the rule-of-thumb should be: only use #ifdefs as a last
resort.

Dave

Gennaro Prota

unread,
Oct 4, 2002, 9:02:57 PM10/4/02
to
On 3 Oct 2002 14:53:07 -0400, ka...@gabi-soft.de (James Kanze) wrote:

>Gennaro Prota <gennar...@yahoo.com> wrote in message
>news:<317mpukljkisa2e4e...@4ax.com>...
>> On 1 Oct 2002 13:08:32 -0400, ka...@gabi-soft.de (James Kanze) wrote:
>
>> >Gabriel Dos Reis <g...@soliton.integrable-solutions.net> wrote
>> >> Gennaro Prota <gennar...@yahoo.com> writes:
>
>> >> [...]
>
>> >> | I suppose in such a case Mr. Kanze would simply include the
>> >> | header with the definition and give up using forward
>> >> | declarations. But that's a bad service to people who have
>> >> | serious compilers: they have to pay for a defect of someone
>> >> | else.
>
>> >> Maybe in such case, Mr. Kanze won't support more than one C++
>> >> implementation ;-)
>
>> >More likely, I'd say that default template arguments are a feature
>> >that isn't ripe enough for production code, and not use them.
>
>> Over-generalized opinion, IMHO.
>
>With a "more likely" qualifier? And followed immediately by an or, and
>other options?

Ahehm... my English again :-( What do you mean?

>The "best" solution, supposing such a thing even exists, depends on a
>lot of issues, most of which we don't know here. Someone put an answer
>in my mouth that is about as far as possible from what I would really
>say.

As I think I cleared up, that someone is not me. I was really
*supposing*.

Also, the fact that I find it unacceptable to give up using default
arguments is *my opinion*, and is partly due to the fact that I find
some VC++ behaviors quite unacceptable as well from a quality point of
view. And since I don't use that compiler unless I'm forced to for my
job, I also hate to be deprived of a feature for its fault. It's as
simple as that (to use the same expression you did).


>It is far more likely that I would suggest one of the solutions I
>list. It is, however, also possible that in certain conditions I would
>recommend not supporting more than one C++ implementation,

Well, my example concerned specifically Boost (more on this later)
and, as you admit, the case of general purpose libraries is quite
different. I make no secret however of the fact that in some cases I
find the Boost developers' effort to support broken compilers a little
excessive.

>or even that
>I would say that his case is one of those rare exceptions which confirm
>the rule.
>
>> >Or adopt a
>> >solution along the lines of what Jean-Marc suggested.
>
>> Ok for me. As long as you accept/admit that you still have a #if/#else
>> for the definition of the macro.
>
>Why? Normally, such macros are defined in a machine/system/compiler
>dependant include file.

I should have been clearer about the fact that I was specifically
referring to boost::dynamic_bitset. AFAIK, this VC++ bug about default
arguments didn't ever come up before on Boost; in fact it isn't a
"constant" bug: sometimes it appears and sometimes not. In our
scenario it did.

In the case of Boost, the machine/system/compiler dependent include
files are the boost/config ones and you would be my hero if you asked
a suitable change to them on the list. I did that, with no success (To
avoid that my words can be interpreted as criticizing the other
developers' opinion: it's not a criticism; and working on those files
is a delicate, dangerous and thankless task, so I'm not blaming the
decision to not touch them - despite the fact that I think they
should. I'm only saying that, given that decision, I had to opt for a
local workaround)

>There is one such file per
>machine/system/compiler combination. Each of the files is in a separate
>directory. And the directory is specified by means of a -I option on
>the command line.

As you know, Boost doesn't work this way.

>At least, that's the way I've always done it.

And I like it.

>It's a shame my site is down, or I could point you to examples.

Well, it's not that difficult to understand. I think I can grasp it
even without an example :-)

Agreed. But "pushing the envelope with the latest features" is
certainly not a good description of using template default arguments
for class templates (I would agree about default template arguments
for function templates when they will be allowed, but that's a
different feature ;-)). The standard library uses them in every place
(std::allocators, std::char_traits, etc...)


>, and 2) any time I refer to
>my experience, it excludes a certain number of things.
>
>I generally try to be careful to distinguish between my personal
>experience ("I don't think I've ever ...") and concrete facts ("In

>å›°.y.z, it says "..."). I certainly hope that I've not given the


>impression that #ifdef is somehow illegal. I do hope that I've given
>the impression that I think that it is something to be avoided, and that
>I think that it can be avoided much more than it is.

Yes. And my point was that it often has drawbacks, and that avoiding
it *may* be a *mean* to avoid those drawbacks. May, or if you prefer,
is *often*.

>> >I think that #ifdef are something to avoid if at all possible. But
>> >like all rules, that is subject to the meta-rule that it can be
>> >violated if the circumstances justify. In this case, all I said was
>> >that in my own experience, I've never encountered a case where the
>> >circumstances justified it. As a statement, it has some
>> >informational value, because I have a fair amount of experience, in
>> >both commercial and industrial domaines. But it is hardly an
>> >absolute, since there are other domains (general purpose libraries,
>> >game software, numerics) in which I've no experience; since even in
>> >the domains I have experience, there might be particular cases that
>> >I have experienced; and since I rather nuanced the statement
>> >anywhere "I don't think I've ever ...". My understanding of English
>> >is that there is a significant difference between "I don't think
>> >I've ever ..." and "No one must ever ...".
>
>> Ok. I see some grudge in your words which is probably due to my phrase
>> "I suppose Mr. Kanze...";
>
>Not just your words. In general, I find it bothersome when people make
>suppositions concerning what I would do when they know very well that
>those suppositions are false.

In my case, I made a genuine supposition, thinking (on the basis of
your previous post) that it was right.

>(Let's face it: as you say, I'm not
>exactly unknown, and pragmatism IS a characteristic of many of my
>postings. I find a solution which works, even if it isn't always 100%
>pure.)
>
>> actually that phrase was meant to say that I wasn't sure about what
>> you would have done in such a case, and that I was just guessing. No
>> intent to be disrespectful on my part, as I tried to make clear from
>> that 'Mr.' in front of your name (intended as a sign of respect).
>

>['Mr.' in front of a name] reads funny in a newsgroup:-).

Ok, my mistake... But absolutely unintentional :-(

[...]


>> Now for a general remark: guidelines are "means", not ends. Take e.g.
>> the "test for features, not for systems".
>
>That is exactly what I have been saying.
>
>Generally speaking, #ifdef's don't help maintainability or readability.
>But we have to deal with variations in systems. So we have to do
>something. Generally speaking, #ifdef's are not good, but if all of the
>alternatives are worse?
>
>The point of citing my experience was to highlight the fact that it is
>probably a fairly rare case where the alternatives are worse.
>
>> Its reason to exist is in the fact that (among other things) the same
>> system may be upgraded/fixed in the future making your implication "if
>> this is system XYZ then feature KXY is missing" suddenly become
>> incorrect.
>
>Your code won't suddenly stop working.

I said the implication (example)

this compiler is XYZ v.5 => it doesn't support KXY

"may" become false :-)


>Some of the programs I use were
>written 15 or more years ago. Some of them are still in K&R C, because
>I've not had the occasion to upgrade them, and they work. Others, just
>as old, now use the STL more or less intensively, because I recently
>added a feature or two, and took advantage of the occasion to upgrade
>them generally.
>
>This doesn't just affect new language features. My point of view
>concerning what is good programming has evolved, too, and even if for
>some reason, the program still had to be in K&R C, I'd "upgrade" it to
>my more recent coding standards.
>
>But I don't think I'm following you. What does this have to do with
>using #ifdef?

Nothing. I just random picked a common guideline to say that it's the
goal that matters, not the guideline per se.

No, it's not the real point. In fact since, as I said, I was thinking
to a Boost example, and Boost is a place where
compatibility/similarity to the standard library is usually considered
important I don't think the idea of dropping the Allocator argument
would have collected many consents (furthermore I didn't even dream of
proposing that; I'm not the designer of the library, and it was not up
to me to propose major changes. The library was already approved after
the formal review at the time that I began to work at it)

The real point (not clearly stated) is that I was forced to use a
local solution. Once you do that, the differences between hiding the
#if/#else behind a macro and using it directly become really a matter
of religion. Yes, I could have used a "bitset config" file. I thought
to that, but I was undecided whether it was a good idea or not. If I
exceed a (arbitrary) critical mass I can always refactor things that
way.

Total agreement (but let us not forget that there are comments too
:-))

But as I said I was referring to Boost, where this macro doesn't exist
and isn't going to be added.
Moreover it's not always as simple as that. Identifying compiler bugs
is not easy. There are cases where the definition of the macro is not
a function (in the mathematical sense) of the compiler only. For the
same compiler (and VC++ is a master in this sort of things) and the
same feature there are situations where you *must* use a workaround
and situations where you must not. And if you have another compiler
that has the opposite behavior then...


>> As an as much questionable device you could decide to #undef the macro
>> at the end of x.hpp.
>
>The macro solution is only viable if the macro is defined in a separate
>header. And potentially used everywhere templates with default
>parameters are involved. So no #undef.

I have already cleared up that I cannot add Boost config macros as I
like.

>> Note also that you can choose to #define the macro in x.hpp (so that
>> it remains 'local' to that file), but if you do so then someone could
>> tell you that there's the problem of keeping it synchronous to
>> x_fwd.hpp. If you want to have one place where the default arguments
>> are specified without having a macro in x_fwd.hpp that you can't
>> #undef at the end of the same file then you have probably to use some
>> helper template, because the second default depends on the first
>> argument:
>
>There are two separate issues. The orginal problem that was given was
>that all of the compilers supported default arguments to templates, but
>that one required the arguments in every template declaration, whereas
>the others, in conformance with the standard, forbid the argument in
>more than one of the template declarations.
>
>My immediate reaction to that is that if compilers vary that much in
>their implementation of the feature, the feature is probably not mature,
>and not ripe enough to be used in production code.

Well, actually of all the compiler I've used there's only one that has
this problem, and it doesn't even appear in every situation. Warning:
to be read as "I don't think I have ever used a compiler that gets
this wrong, except one" ;-)


>But this is only a
>very general guideline, and subject to a lot of exceptions. A macro
>FOLLOWUP_DEFAULT_TEMPLATE_ARG, along the lines of the above, handles
>this in what is in my opinion an acceptable way as well. (Although as
>you say, anytime you have to repeat the same information, you are
>creating a maintenance headache. The fact that one compiler requires
>that you repeat this information is another indication that perhaps you
>should do without default template arguments for the moment.)

I don't know. If I give up using this or that construct each time that
*one* compiler has a problem with it I wonder what could I really
write, especially when writing templatized generic components.

>
> [example cut...]
>
>> Note how I'm pointing out the fact that when you work in team you have
>> to satisfy others too.
>
>Quite. That's what coding guidelines and code review is for.
>
>Hopefully, you will have discussed the problem and agreed on a standard
>solution for it before you encounter it.

In the example above? No. As already pointed out, each time I ask for
some modification to the boost config files I get the same number of
replies that I would get by asking on this newsgroup how to program in
CLOS :-) So I had just to use a local macro (by 'local' I mean
#undef'd in the same source file in which it is #defined).

Just to convince yourself you might want to look at these:


a) http://aspn.activestate.com/ASPN/Mail/Message/1327922

Note that I was only asking for a change to the docs, and for the
addition of a BOOST_NO_NEW_IOSTREAMS macro (a 2 or 3-line change in
one of the lib config headers)


b) http://aspn.activestate.com/ASPN/Mail/Message/1379052

where I was asking for a simple #define to easily identify the library
after (something which can be useful for various things, e.g. user
reports)

> In that case, you use the
>standard solution. Unless there are really overwhelming reasons to
>deviate. The macro based solution *doesn't* work if you invent it on
>your own, and use it without telling anyone. Do that, and you WILL have
>the maintainance problem that Gerhard Menzl is worried about.

Well, I'm extremely pedantic about coding, so please don't
misunderstand me. However I think there are comments too. For instance
in my file I wrote (I'm not *defending* my solution: I'm quite
interested in yours. And I will be glad to put it in the files, give
you credit and put myself in the wicked's list :-) I have explained
what my choices actually were)

#ifdef BOOST_MSVC
// in certain situations VC++ requires a redefinition of
// default template arguments, in contrast with 14.1/12
//
# define BOOST_WORKAROUND_REPEAT_DEFAULT_TEMPLATE_ARGUMENTS // macro
'local' to this file
#endif


>
>> Actually the reason why I have used a "direct"
>> #if/#else for dynamic_bitset is the sort of fear that everybody have
>> for macros. They will tell me, I thought, that macros are best
>> avoided.
>
>And conditional compilation is best avoided. And complex code is best
>avoided. And wouldn't it be nice if nothing we did were every more
>complex than "hello, world". Macros ARE best avoided. But you have a
>problem to be solved, and you have a limited number of possible
>solutions. None of which are particularly nice.
>
>> To be honest I have used a macro anyway, i.e. the highly readable (;-)
>> BOOST_WORKAROUND_REPEAT_DEFAULT_TEMPLATE_ARGUMENTS but that's for the
>> good reason, we all know (As an aside I think that the rule that long
>> names are *always* clearer is quite stupid too. But let us not put too
>> many irons in the fire).
>
>Above all, it works because 1) there are other macros with names like
>BOOST_WORKAROUND_WHATEVER_ELSE_DOESN_T_WORK

Uh? Are there other macro names that begin with BOOST_WORKAROUNDxxx in
Boost?

>, 2) this is the standard
>way of handling portability issues in Boost

I thought I had invented that! :-) Well, seriously: there's no other
macro with that name convention in Boost (yet?).

> -- anyone reading Boost code
>recognizes immediately what is taking place, and 3) the macros are
>defined in a separate, centrally maintained file -- when porting to a
>new system, someone creates a new version of this file, and (if you are
>very, very lucky) all of the code just magically works with the new
>system.

Agreed. But as I said nobody is willing to modify the boost config
files (which is admittedly a thankless task).


>> IMHO, that (guessed but, you know, possible) objection means confusing
>> the mean for the goal. However one has to come to a compromise with
>> the opinion of others of course.
>
>> Granted, as you say there's a meta-rule that says a rule can be broken
>> if you can justify the reasons for breaking; but everything depends on
>> what other things about "justifying". I think for instance that main()
>> should have a return statement, and there's no reason for it to be a
>> special case.
>
>I do to. But not to the point of inserting a return statement if the
>local consensus says not to.
>
>> Also I think that prohibiting (void*)0 to be a null pointer constant
>> is a silly and gratuitous incompatibility with C, and that the
>> "rationale" often quoted for not allowing forward declarations of
>> enums is silly.
>
>I do to, but in this case, the consensus is actually formalized in the
>standard. I use NULL (unless the client coding conventions insist
>otherwise), but in no case would I even think of using (void*)0.

Me too. If nothing else, because I would have to convince my compiler
first ;-)

>> However there are top-level experts that would kill me for these
>> assertions.
>
>If your assertion is that you think X is better, in these cases, anyone
>who would kill you for it isn't an expert. An expert might have other
>preferences (I think that Stroustrup prefers 0 to NULL), but any expert
>will recognize that there is a lot of room for different opinions with
>regards to these two points.

Though I'm sure that you understood very well my point, let me clarify
for those who didn't: it's not a matter of 0 vs. NULL; it's the fact
that it (the null pointer constant) shouldn't have integer type.

Actually my opinion is that it was better to introduce a new
(incomplete) type for that constant as Francis Glassborow has
suggested in the past.

As to using 0 vs. NULL I prefer NULL (mainly in the hope that I can
grep and replace it easily if a true null pointer constant will be
introduced in C++) but generally my position in this sorts of things
is: decide what you want and then tell me. I don't want to be
involved. Frankly. I can program in both ways and I let others to tore
the dresses up each other if they want. Then, when they reached a
consensus... (well, they usually don't; but they have to decide sooner
or later, and when they retire to have a quick going-over I can start
programming ;-)) If the language had a true, type-safe,
overload-compatible null pointer constant then we could start
discussing on real technical basis.


>> As you see, it's a matter of opinions (despite the fact that we try to
>> make everything appear as pure, objective, incontrovertible
>> logic). I'm sure there's people around that is convinced of some
>> incontestable reason why #ifndef should be used for include guards
>> instead of #if !defined, and maybe that's one of the issues one can
>> arise to beat the record of the longest c.l.c++.m thread too :-)
>
>There's no technical reason, or the technical reasons aren't
>overwhelming. But there may be non-technical reasons. In all of the
>places I've worked, everyone has always used #ifndef for the include
>guides.

But, honestly, have you ever checked that absolutely in no place
there's a #if !defined? Since your firm assertion made me curious I
checked e.g. the boost headers. Just take a look ;-)

Well, if you have whatever automatism to insert include guards then it
can be that you really have all #ifndef, but from that fact to the
point of asserting, as you do below, that it's a *definite error* to
have both forms I would have some reservations.

Actually, let's face it: C++ doesn't have a built-in mechanism to
realize include guards because they *can be* realized within the
language itself. Ok, no need to make a federal case out of it. But if
then people make a federal case out of *how* to realize it and of
whether to use #ifndef or #if !defined then please do something to
introduce a

#include_guard

directive. Please! :-)


>IMHO, it would definitely be an error to be different with
>regards to this. Not for any technical reason, but differences tend to
>be remarked.

....

>If there's a serious technical problem which requires a
>different answer, this is a good thing. For include guards, it is
>definitly not a good thing.

Ehmm... sounds like a prophecy to me :-) (In the sense that it's quite
enigmatic. Can you clear up?)

P.S. An entreaty: this subthread is experiencing longer and longer
messages. If you reply, could you who have a much better mastery of
the language than me try summarizing? This has certainly exceeded the
critical mass of understandability for the present foreign guy! :-)


Genny.

Mary K. Kuhner

unread,
Oct 11, 2002, 4:53:04 AM10/11/02
to
In article <d6651fb6.02092...@posting.google.com>,
James Kanze <ka...@gabi-soft.de> wrote:

>I don't think I've ever used an #ifdef in production code. There are


>two types of differences between systems:

> - One system supports features that the other system lacks. If you
> need to target both systems, you don't use these features. It's as
> simple as that.

> - Both systems support the same functionnality, but in different

> ways. The obvious examples are sockets or threads. [...]

>Can you show me an example of something else? Where you might actually
>want to use an #ifdef in the code. I've never yet encountered a case
>where I would want to, although I think I would resist if I did; I
can't
>think of anything which would make the code harder to maintain.

Deep in the inner number-crunching routines of our portable scientific
software we have:

#ifdef MAC
eventloop();
#endif

Without this, biologists with Mac OS9 simply won't use our program--it
ties up their machine unacceptably. (I got to see this first hand at
a workshop we gave--it was unbelievably obnoxious.) Leaving out this
feature is not acceptable as it essentially kills 35% of our 'market'
for the program. I would be happy to hear of other ways to handle this
problem. They need to impose minimal overhead, as this *is* tight
number-crunching code.

Mary Kuhner mkku...@gs.washington.edu

Randy Maddox

unread,
Oct 11, 2002, 3:43:51 PM10/11/02
to
"JKB" <burr...@seanet.com> wrote in message
news:<upjueqk...@corp.supernews.com>...

> "James Kanze" <ka...@gabi-soft.de> wrote
> > I don't think I've ever used an #ifdef in production code.
>
> How do you handle the situation where a facility is present on two
> platforms, but presented differently? A simple example:
case-insensitive
> string compare is provided by Windows and Linux, but they're called
> different things. I write:
>
> int compare_nocase(const char* L, const char* R)
> {
> #ifdef WIN32
> return ::stricmp(L,R);
> #endif
>
> #ifdef LINUX
> return ::strcasecmp(L,R);
> #endif
> }
>
> I've also seen this done by #defining one as the other, but even then
one
> would conditionally compile the define.
>
>
> -- jkb

I do not object to conditional compilation, if and as appropriate, but
the technique shown here can easily lead to problems, not in this
particular case, but in others, say with void as the return type, if
none of the symbols checked for is defined. Since you are explicitly
supporting multiple platforms, IMHO, you should also detect when the
code is not being compiled on one of those platforms. For the above
this would be as:

#if defined(WIN32)
return ::stricmp(L,R);
#elif defined(LINUX)
return ::strcasecmp(L,R);
#else
#error This code may be compiled only for WIN32 or LINUX
#endif

Randy.

0 new messages