Boost logo

Boost :

From: Greg Colvin (gcolvin_at_[hidden])
Date: 2001-10-25 11:58:25


From: Ed Brey <edbrey_at_[hidden]>
> From: "Greg Colvin" <gcolvin_at_[hidden]>
>
> > namespace constants {
> >
> > // an example constant, suitable for everyday abuse
> > static const struct pi_ {
> > pi_(){}
> > inline operator long double() const {
> > return 3.141592653589793238462643383279502884197L;
> > }
> > } pi;
> >
> > // a generic constant generator
> > template<typename T, typename V> inline T constant(const V& v) {
> > return static_cast<T>(v);
> > }
> >
> > // example specializations of the constant generator
> > template<> inline float constant(const pi_&) {
> > return 3.141593F;
> > }
> > template<> inline double constant(const pi_&) {
> > return 3.14159265358979;
> > }
> > template<> inline long double constant(const pi_&) {
> > return 3.141592653589793238L;
> > }
> > }
>
> Very interesting. It shows promise of a single interface for specific and generic use.
>
> But alas, I can't make it work. The compiler complains about multiple functions named "constant" that differ only by return type.

EDG compiles this fine in --strict mode. I've attached my test program.

> There is also the same constructor issue that Michael's pattern has. Here's the summary:
> - With the constructor, VC generates code for each constant, whether referenced or not.

I'd hate to give up a good interface just because some systems generate
uneccessarily bad code. I expect that on most systems we can tweak
the implementation to solve such problems.

> - Without the constructor, g++ complains that "pi" is uninitialized.

Without the constructor EDG says

        error: const variable "constants::pi" requires an
          initializer -- class "constants::pi_" has no explicitly declared
          default constructor
        } pi;
            ^

But it doesn't complain without --strict.

> There are a few possible solutions, however. If VC is the only compiler that becomes inefficient in the face of the constructor,
conditionally compile it away for VC. If other compilers prefer to not see the constructor, change the definition of "pi" to
>
> double const pi_ pi = {};
>
> However, the {} notation breaks VC, so it would have to conditionally compiled out in that case. I don't know what the notation
does to the efficiency on other compilers.
>
> Of course, there is still the option of simply providing a bunch of simple double constants for non-generic uses, and then a
separate simple function interface for generic uses, like this

I'd prefer long double constants.

> template<typename T>
> struct constants {}
>
> template<>
> struct constants<double> {
> static double pi() {return 3.14;}
> }

Yes, I like this as well.

> Given the pitfalls with the fancy template magic, I'm starting lean towards the simpler approach. This would cover the common
cases quite well. It doesn't provide for fanciness such as hand-crafted binary constants in the initial implementation, but I
question the value of such items that are opaque to the compiler anyway (e.g. they are not subject to constant folding).
>
> If the interface is kept restrained, the implementation for the non-generic constants could be tweaked at any time. Of course, we
may find it more valuable to allow taking pointers and references to constants than to allow tweaking the implementation. The
former doesn't seem to be valuable very often, but then again, neither does the latter.

Of course Beman says "Please do not make any design decisions for math
constants based on brain-dead compilers."




Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk