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

Template parameters of type float?

138 views
Skip to first unread message

Siegfried Heintze

unread,
Dec 1, 2001, 8:25:23 AM12/1/01
to
I tried posting this last week on comp.lang.c++.moderated but my posting
never showed up so I'm trying again.
Todd Veldhuizen published some brilliant articles in C++ Report and
apparently in the book C++ Gems. I've tried to order the book but it is out
of print.

I've successfully reconstructed some of his techniques, but the GNU V2 C++
compiler tells me I cannot use floats/doubles as template arguments. The
compiler's error message says they are not standard.

Is this true? Why?

Where can I access Todd's code?
I'm looking for additional material for my advanced C++ classes so I'm
looking for some interesting techniques.

Thanks,
Siegfried

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

[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std...@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]

Terje Slettebø

unread,
Dec 5, 2001, 9:37:31 AM12/5/01
to
"Siegfried Heintze" <sieg...@heintze.com> wrote in message
news:u0cvtii...@corp.supernews.com...

> I tried posting this last week on comp.lang.c++.moderated but my posting
> never showed up so I'm trying again.
> Todd Veldhuizen published some brilliant articles in C++ Report and
> apparently in the book C++ Gems. I've tried to order the book but it is
out
> of print.
>
> I've successfully reconstructed some of his techniques, but the GNU V2 C++
> compiler tells me I cannot use floats/doubles as template arguments. The
> compiler's error message says they are not standard.
>
> Is this true? Why?

Yes.

I guess the reason is, that it could be hard to pick the right template
instantitiation, because of possible roundoff errors. Consider the
following:

template<float n>
void f(n);

template<0.3333>
void f() { ...} // Specialization for 0.3333

f(1/3); // Call the specialization, or...? No. It's not exactly the same
number, so it wouldn't be correct.


> Where can I access Todd's code?
> I'm looking for additional material for my advanced C++ classes so I'm
> looking for some interesting techniques.

If you haven't, you may also want to check out his homepage
(http://extreme.indiana.edu/~tveldhui/). That's where I found out about
this, too, and the articles on expression templates and template
metaprogramming, really showed me the possibilities of what you can do with
templates.

There's a lot of information there, including links to other places, and
code.

There's also another book that deals with such template metaprogramming,
"Generative Programming." Highly recommended.


Regards,

Terje Slettebo
---

Terje Slettebø

unread,
Dec 5, 2001, 9:37:56 AM12/5/01
to
> "Siegfried Heintze" <sieg...@heintze.com> wrote in message
> news:u0cvtii...@corp.supernews.com...
> > I tried posting this last week on comp.lang.c++.moderated but my posting
> > never showed up so I'm trying again.
> > Todd Veldhuizen published some brilliant articles in C++ Report and
> > apparently in the book C++ Gems. I've tried to order the book but it is
> out
> > of print.
> >

An addition to my last posting.

Sorry, the way this would be done, if float parameters were supported, is
the following. I usually test things, before submitting, but in this case, I
couldn't, as float parameters aren't supported.

template<float>
void f(); // Template declaration

template<>
void f<1.3333>() {} // Specialize for 1.3333

f<1/3>f(); // Call the specialization, or...? No. It's not exactly the same


number, so it wouldn't be correct.


Regards,

Terje Slettebo
---

Richard Smith

unread,
Dec 5, 2001, 9:38:21 AM12/5/01
to
"Siegfried Heintze" <sieg...@heintze.com> wrote in message
news:u0cvtii...@corp.supernews.com...
> I tried posting this last week on comp.lang.c++.moderated but my posting
> never showed up so I'm trying again.
> Todd Veldhuizen published some brilliant articles in C++ Report and
> apparently in the book C++ Gems. I've tried to order the book but it is
out
> of print.
>
> I've successfully reconstructed some of his techniques, but the GNU V2 C++
> compiler tells me I cannot use floats/doubles as template arguments. The
> compiler's error message says they are not standard.
>
> Is this true? Why?

Yes, it is true. (Although I thought that g++ did support floating point
template arguments as an extension provided that you're not
cross-compiling.)

Consider the following code:

template <float f> class foo { ... };
foo<1E6 + 1E-6> my_foo;

What should the compiler generate? Perhaps on one some floating point
architecture 1E6 + 1E-6 == 1E6, but on another it might be represented
exactly, and so the compiler has to know about the details of target
floating-point architecture to be able to run instantiate the template.
This is easy enough if the compiler is running on the target
architecture --- it can just do the calculation and find out the answer, but
if you are cross-compiling, the compiler would have to be able to synthesise
the floating point behaviour of every intended target architecture. And
thankfully the Standards Committee decided that this would be unreasonable.

--
Richard Smith
---

Nithyanandham

unread,
Dec 5, 2001, 9:41:29 AM12/5/01
to
Siegfried Heintze wrote:

> I've successfully reconstructed some of his techniques, but the GNU V2 C++
> compiler tells me I cannot use floats/doubles as template arguments. The
> compiler's error message says they are not standard.
>
> Is this true?

Yes.
>From C++ standard: -
A non-type template-parameter shall not be of type void. A non-type
template-parameter shall not be of floating type. [Example:
template<double d> class X; // error
template<double* pd> class Y; // ok
template<double& rd> class Z; // ok
--end example]


> Why ?

The floating point computation can't done at the compile time and remember
floating point values are implementation dependent. So,template instantiation
can't be done if the template argument is of type float/double.

--

Nithyanand.
Siemens, Bangalore, India.
(Opinions expressed are my own and do not reflect the opinions of my employer,
Siemens)
---

Sergey P. Derevyago

unread,
Dec 5, 2001, 9:42:10 AM12/5/01
to
Siegfried Heintze wrote:
> compiler tells me I cannot use floats/doubles as template arguments. The
> compiler's error message says they are not standard.
>
> Is this true? Why?
Different platforms do FP with different precision. So the meaning of your
code (your type system) can be silently affected.

PS IMHO some kind of FP template parameters can really be useful. So the
original rule should be relaxed in certain ways.
--
With all respect, Sergey. http://cpp3.virtualave.net/
mailto : ders at skeptik.net
---

James Kuyper Jr.

unread,
Dec 6, 2001, 12:38:27 AM12/6/01
to
Terje Slettebø wrote:
>
> > "Siegfried Heintze" <sieg...@heintze.com> wrote in message
> > news:u0cvtii...@corp.supernews.com...
> > > I tried posting this last week on comp.lang.c++.moderated but my posting
> > > never showed up so I'm trying again.
> > > Todd Veldhuizen published some brilliant articles in C++ Report and
> > > apparently in the book C++ Gems. I've tried to order the book but it is
> > out
> > > of print.
> > >
>
> An addition to my last posting.
>
> Sorry, the way this would be done, if float parameters were supported, is
> the following. I usually test things, before submitting, but in this case, I
> couldn't, as float parameters aren't supported.
>
> template<float>
> void f(); // Template declaration
>
> template<>
> void f<1.3333>() {} // Specialize for 1.3333

Do you mean to write 0.3333?

> f<1/3>f(); // Call the specialization, or...? No. It's not exactly the same
> number, so it wouldn't be correct.

You're right; 0 is very different from 1.3333. :-)

Perhaps you intended to write 4.0/3.0 in that case?

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

[ comp.std.c++ is moderated. To submit articles, try just posting with ]


[ your news-reader. If that fails, use mailto:std...@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]

Terje Slettebø

unread,
Dec 7, 2001, 7:02:51 AM12/7/01
to
"James Kuyper Jr." <kuy...@wizard.net> wrote in message news:<3C0E33F5...@wizard.net>...

> Terje SlettebC8 wrote:
> >
> > > "Siegfried Heintze" <sieg...@heintze.com> wrote in message
> > > news:u0cvtii...@corp.supernews.com...
> > > > I tried posting this last week on comp.lang.c++.moderated but my posting
> > > > never showed up so I'm trying again.
> > > > Todd Veldhuizen published some brilliant articles in C++ Report and
> > > > apparently in the book C++ Gems. I've tried to order the book but it is
> out
> > > > of print.
> > > >
> >
> > An addition to my last posting.
> >
> > Sorry, the way this would be done, if float parameters were supported, is
> > the following. I usually test things, before submitting, but in this case, I
> > couldn't, as float parameters aren't supported.
> >
> > template<float>
> > void f(); // Template declaration
> >
> > template<>
> > void f<1.3333>() {} // Specialize for 1.3333
>
> Do you mean to write 0.3333?

Yeah. :)



> > f<1/3>f(); // Call the specialization, or...? No. It's not exactly the same
> > number, so it wouldn't be correct.


Regards,

Terje Slettebo
---

Allan W

unread,
Dec 7, 2001, 9:50:56 AM12/7/01
to
"Richard Smith" <ric...@ex-parrot.com> wrote

> Consider the following code:
>
> template <float f> class foo { ... };
> foo<1E6 + 1E-6> my_foo;
>
> What should the compiler generate? Perhaps on one some floating point
> architecture 1E6 + 1E-6 == 1E6, but on another it might be represented
> exactly, and so the compiler has to know about the details of target
> floating-point architecture to be able to run instantiate the template.
> This is easy enough if the compiler is running on the target
> architecture --- it can just do the calculation and find out the answer, but
> if you are cross-compiling, the compiler would have to be able to synthesise
> the floating point behaviour of every intended target architecture. And
> thankfully the Standards Committee decided that this would be unreasonable.

Doesn't the cross-compiler need intimate knowledge of the intended
target architecture anyway? When the cross-compiler turns C++
source code into target-dependant machine code, isn't this where
the "portable" part of the code becomes "targeted"?

Consider this code:

double foo = 1.23456;

Doesn't the compiler have to know *exactly* what 1.23456 is going to
look like in memory for the target machine, so that it can write out
the correct byte pattern? If so, it's not much of a leap for the
compiler to calculate 1E6 + 1E-6 with as much accuracy as possible.

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

[ comp.std.c++ is moderated. To submit articles, try just posting with ]


[ your news-reader. If that fails, use mailto:std...@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]

Al Grant

unread,
Dec 9, 2001, 9:32:06 PM12/9/01
to
"Allan W" <all...@my-dejanews.com> wrote in message
news:7f2735a5.01120...@posting.google.com...

> Consider this code:
>
> double foo = 1.23456;
>
> Doesn't the compiler have to know *exactly* what 1.23456 is going to
> look like in memory for the target machine, so that it can write out
> the correct byte pattern?

No, it only needs to know its size. It also has to be able to
convert this literal to an integer (probably '1').

There does appear to be a language issue here in that it is
implementation-defined [2.13.3] whether, say,

0.99999999999999999999999999999999999999999999999999999

rounds up or down. And that will affect the resulting integral
value in an integral constant-expression. So that means that
template instantiation etc. are _already_ dependent on the
compiler's floating point model, though that may not be the
same as the target floating point model.

For example on Comeau,

template<int N> struct S { };

template<> struct S<(int)0.999999999999999944> { };
template<> struct S<(int)0.999999999999999945> { };
template<> struct S<(int)0.999999999999999946> { };

the second specialization is distinct from the first, but the
third is identical to the second (in Comeau's FP model), and is
faulted.

So the argument "allowing template parameters of type float
would introduce a model dependency into template expansion" is
bogus. The above example suggests that allowing floating
point parameters with floating-point literal arguments
introduces no new dependency - just the existing dependency
on whether two floating-point literals denote the same value.
---

Jeff Koftinoff

unread,
Dec 9, 2001, 9:32:25 PM12/9/01
to
In article <7f2735a5.01120...@posting.google.com>,
all...@my-dejanews.com (Allan W) wrote:

<snip>


>
> Doesn't the cross-compiler need intimate knowledge of the intended
> target architecture anyway? When the cross-compiler turns C++
> source code into target-dependant machine code, isn't this where
> the "portable" part of the code becomes "targeted"?
>
> Consider this code:
>
> double foo = 1.23456;
>
> Doesn't the compiler have to know *exactly* what 1.23456 is going to
> look like in memory for the target machine, so that it can write out
> the correct byte pattern? If so, it's not much of a leap for the
> compiler to calculate 1E6 + 1E-6 with as much accuracy as possible.
>

Unfortunately it is too much of a leap. Because you don't want 'as much
accuracy as possible', you want 'identical accuracy as the target platform
would have'.

A real example that I ran into:
float a,b,c,d;
a=(b*c)+d;

Can compile to one instruction on some DSP's. float is 32 bits. but
(b*c)+d is calculated with higher precision internally and then rounded to
32 bits. Other targets don't.

Anyways, there is a way to do what you want in a roundabout way. depending
what you actually want, it isn't clear.

struct half
{
static inline float value() { return 0.5f; }
};

struct one_and_one_third
{
static inline float value() { return 1.333333333f; }
};

template<typename T>
void f()
{
// do something with T::value()
}

template<>
void f<one_and_one_third>()
{
// do something with one_and_one_third::value()
}

But, no arithmetic on the parameter is allowed. It still is useful though
in terms of optimizing code to use constants instead of memory accesses on
some platforms.

If you wanted to get very ugly you could reinterpret_cast<> your float to
an unsigned long and back.... ick!

--
jeff koftinoff <je...@jdkoftinoff.com>
---

James Kanze

unread,
Dec 10, 2001, 7:54:20 PM12/10/01
to
"Richard Smith" <ric...@ex-parrot.com> wrote in message
news:<1007475622.16067....@news.demon.co.uk>...

> > Is this true? Why?

> Consider the following code:

I don't think difficulty of implementation is the only issue.
Consider the following:

foo<1E6+1E-6> foo1 ;
foo<1E6> foo2 ;

Do foo1 and foo2 have the same type or not?

--
James Kanze mailto:ka...@gabi-soft.de
Beratung in objektorientierer Datenverarbeitung --
-- Conseils en informatique orientée objet
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany, Tél.: +49 (0)69 19 86 27

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

[ comp.std.c++ is moderated. To submit articles, try just posting with ]


[ your news-reader. If that fails, use mailto:std...@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]

Steve Clamage

unread,
Dec 11, 2001, 4:07:01 AM12/11/01
to
On 7 Dec 2001, Allan W wrote:
> "Richard Smith" <ric...@ex-parrot.com> wrote
> > Consider the following code:
> >
> > template <float f> class foo { ... };
> > foo<1E6 + 1E-6> my_foo;
> >
> > What should the compiler generate? Perhaps on one some floating point
> > architecture 1E6 + 1E-6 == 1E6, but on another it might be represented
> > exactly, and so the compiler has to know about the details of target
> > floating-point architecture to be able to run instantiate the template.
> > This is easy enough if the compiler is running on the target
> > architecture --- it can just do the calculation and find out the answer, but
> > if you are cross-compiling, the compiler would have to be able to synthesise
> > the floating point behaviour of every intended target architecture. And
> > thankfully the Standards Committee decided that this would be unreasonable.
>
> Doesn't the cross-compiler need intimate knowledge of the intended
> target architecture anyway? When the cross-compiler turns C++
> source code into target-dependant machine code, isn't this where
> the "portable" part of the code becomes "targeted"?
>
> Consider this code:
>
> double foo = 1.23456;
>
> Doesn't the compiler have to know *exactly* what 1.23456 is going to
> look like in memory for the target machine, so that it can write out
> the correct byte pattern? If so, it's not much of a leap for the
> compiler to calculate 1E6 + 1E-6 with as much accuracy as possible.

The host must know the format of floating-point values on the
target machine, but that's not the same thing as simulating
floating-point arithmetic exactly. Apart from the obvious --
number of bits in exponent and fraction, and whether the exponent
is base 2 -- what's the behavior for
- round-off (how many guard bits, if any)
- sub-normal numbers (flush to zero, or compute)
- NaN (how many kinds, what semantics)
- Infinities (none, plus/minus, or just one)
I've probably left off a few things.

The question is whether you require in the standard that the host
machine duplicate all floating-point results exactly.

--
Steve Clamage, stephen...@sun.com
---

Al Grant

unread,
Dec 11, 2001, 9:15:05 AM12/11/01
to
"James Kanze" <ka...@gabi-soft.de> wrote in message
news:d6651fb6.01121...@posting.google.com...

> I don't think difficulty of implementation is the only issue.
> Consider the following:
>
> foo<1E6+1E-6> foo1 ;
> foo<1E6> foo2 ;
>
> Do foo1 and foo2 have the same type or not?

Consider the following:

foo<(int)1.000000000001E6> foo1;
foo<(int)1E6> foo2;

Do foo1 and foo2 have the same type or not? The above
code is Standard C++. What conceptual issue does your
example demonstrate that is not already in the language?
---

Richard Smith

unread,
Dec 11, 2001, 5:23:42 PM12/11/01
to
"James Kanze" <ka...@gabi-soft.de> wrote in message
news:d6651fb6.01121...@posting.google.com...
> "Richard Smith" <ric...@ex-parrot.com> wrote in message
> news:<1007475622.16067....@news.demon.co.uk>...

[snip]

> > Consider the following code:
> >
> > template <float f> class foo { ... };
> > foo<1E6 + 1E-6> my_foo;
> >
> > What should the compiler generate?

[snip]

> I don't think difficulty of implementation is the only issue.
> Consider the following:
>
> foo<1E6+1E-6> foo1 ;
> foo<1E6> foo2 ;
>
> Do foo1 and foo2 have the same type or not?

True. But this applies to integers too. As Sergey Derevyago asked in the
"Implementation dependence and template parameters" thread, are the
following the same type?

template <int TI> struct A { };
A<4294967291> a;
A<-5> b;

--
Richard Smith
---

Allan W

unread,
Dec 12, 2001, 2:26:38 AM12/12/01
to
> "Allan W" <all...@my-dejanews.com> wrote

> > Consider this code:
> >
> > double foo = 1.23456;
> >
> > Doesn't the compiler have to know *exactly* what 1.23456 is going to
> > look like in memory for the target machine, so that it can write out
> > the correct byte pattern?

"Al Grant" <tna...@arm.REVERSE-NAME.com> wrote


> No, it only needs to know its size. It also has to be able to
> convert this literal to an integer (probably '1').

I think you're missing my point.

What does a compiler do? It accepts source code and emits machine
code (or it emits object code, which is then translated into
machine code). A cross-compiler generates machine code for a
different computer than the one it runs on, but otherwise is the
same thing.

Now, assume that the compiler needs to assign the value 1.23456 to
the variable foo. It has to generate machine code that does this.
On most CPUs this will involve some form of the "Move" instruction,
which copies data from one place in memory to another (or possibly
loads data from the instruction stream to somewhere in memory).
The compiler is also responsible for generating the value 1.23456
in the first place.

The compiler can't do this unless it knows what the value 1.23456
looks like -- what bit pattern will be used by the number in memory.
The text "1.23456" is long gone by the time the program is loaded
into memory -- we need a binary equivalent instead. That binary
equivalent is produced by the compiler.

Am I making sense here? Maybe someone else can see what I'm trying
to say, and can explain it better.

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

[ comp.std.c++ is moderated. To submit articles, try just posting with ]


[ your news-reader. If that fails, use mailto:std...@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]

James Kuyper Jr.

unread,
Dec 12, 2001, 9:35:11 PM12/12/01
to
Allan W wrote:
>
> > "Allan W" <all...@my-dejanews.com> wrote
> > > Consider this code:
> > >
> > > double foo = 1.23456;
> > >
> > > Doesn't the compiler have to know *exactly* what 1.23456 is going to
> > > look like in memory for the target machine, so that it can write out
> > > the correct byte pattern?
>
> "Al Grant" <tna...@arm.REVERSE-NAME.com> wrote
> > No, it only needs to know its size. It also has to be able to
> > convert this literal to an integer (probably '1').
>
> I think you're missing my point.
>
> What does a compiler do? It accepts source code and emits machine
> code (or it emits object code, which is then translated into
> machine code). A cross-compiler generates machine code for a
> different computer than the one it runs on, but otherwise is the
> same thing.
>
> Now, assume that the compiler needs to assign the value 1.23456 to
> the variable foo. It has to generate machine code that does this.
> On most CPUs this will involve some form of the "Move" instruction,
> which copies data from one place in memory to another (or possibly
> loads data from the instruction stream to somewhere in memory).
> The compiler is also responsible for generating the value 1.23456
> in the first place.

No, it's not. It's only responsible for generating code that ends up
creating that value. How it achieves that result is an implementation
detail, not specified by the standard.

> The compiler can't do this unless it knows what the value 1.23456
> looks like -- what bit pattern will be used by the number in memory.

Yes, but it can do something quite different that doesn't carry that
requirement. See below.

> The text "1.23456" is long gone by the time the program is loaded
> into memory -- we need a binary equivalent instead. That binary

That's one possibile way to do it, but it's also possible to retain that
text.

> equivalent is produced by the compiler.
>
> Am I making sense here? Maybe someone else can see what I'm trying
> to say, and can explain it better.

Oh, you're explaining it fairly well, you've just missed a possibility.
An implementation is free to translate

double foo = 1.2345;

into machine code that is the equivalent of

double foo = atof("1.2345");

which removes any need for the cross-compiler to know the details of the
floating point implementation on the target machine. The target machine
can contain the actual implementation of atof().
---

Al Grant

unread,
Dec 13, 2001, 6:34:03 AM12/13/01
to
"Allan W" <all...@my-dejanews.com> wrote in message
news:7f2735a5.01121...@posting.google.com...

> > No, it only needs to know its size. It also has to be able to
> > convert this literal to an integer (probably '1').
>
> I think you're missing my point.

I don't think you have a valid point about the language.
What the average compiler may do is another thing.

> What does a compiler do? It accepts source code and emits machine
> code (or it emits object code, which is then translated into
> machine code). A cross-compiler generates machine code for a
> different computer than the one it runs on, but otherwise is the
> same thing.

But C++ implementations don't have to be compilers.

> Now, assume that the compiler needs to assign the value 1.23456 to
> the variable foo. It has to generate machine code that does this.
> On most CPUs this will involve some form of the "Move" instruction,
> which copies data from one place in memory to another

Maybe it could embed the numbers as strings in the object
file, and call sscanf at program load time.

> The compiler can't do this unless it knows what the value 1.23456
> looks like -- what bit pattern will be used by the number in memory.
> The text "1.23456" is long gone by the time the program is loaded
> into memory -- we need a binary equivalent instead. That binary
> equivalent is produced by the compiler.
>
> Am I making sense here?

You're coherent, but you are asserting lots of things without
reference to the standard.

The standard says:

- if a literal's value is not in the range of representable
values for its type then the program is ill-formed. But you
can check that without knowing the exact representation.

- floating-point literals may be cast to integers in
integral constant-expressions. But you may be able to do
that without knowing the exact representation too, even if
you interpret the standard, as I think you must, to mean
that you must get the integer that results from a truncation
of the appropriately typed representable floating-point
value denoted by the literal. (Rounding the literal down
to an integer directly would be easy, of course.)

In particular, there appears to be no requirement on implementations
to know anything about the representation of negative floating-point
numbers. So how can there possibly be a requirement on them to be
able to do general arithmetic?

It's bad enough that the conformity of programs can depend on the
mapping of characters to integers (e.g. are
template ... <65>
template ... <'A'>
the same thing?) But at least that problem was inherited from C.
---

0 new messages