#include <iostream>
#include <cmath>
using namespace std;

// The GCC 2.95.x requires some workarounds. The operators below need to be
// defined in a class which resides in the global namespace and the implementation
// of the generic cast operator is overly complex. A simple 'return F< U >()();'
// is enough for good compilers, but the GCC 2.95.x gives an ICE for it.

// Generic base class for all constants
template< class T, template< typename > class F > struct boost_math_constant
{
    // A cast-to-anything-operator :)
    template< typename U > operator U() const { F< U > tmp; return tmp(); }
    
#define ADD_OPERATOR( OP ) \
    template< typename U > friend U operator OP( const T& lhs, const U& rhs ) \
    { U nrv( static_cast< U >( lhs ) ); nrv OP##= rhs; return nrv; } \
    template< typename U > friend U operator OP( const U& lhs, const T& rhs ) \
    { U nrv( lhs ); nrv OP##= static_cast< U >( rhs ); return nrv; } \
    template< typename U > friend U& operator OP##=( U& lhs, const T& rhs ) \
    { lhs OP##= static_cast< U >( rhs ); return lhs; }

    ADD_OPERATOR( + );
    ADD_OPERATOR( - );
    ADD_OPERATOR( * );
    ADD_OPERATOR( / );
#undef ADD_OPERATOR
};

namespace boost
{
    namespace math
    {
        // Forward the workaround-class to where it belongs
        template< class T, template< typename > class F > struct constant : boost_math_constant< T, F > {};

        // Here's the definition for pi for all types (can be extended by UDTs):
        template< typename T > struct pi_value;
        template<> struct pi_value< float > { float operator()() const { return 3.14; } };
        template<> struct pi_value< double > { double operator()() const { return 3.1416; } };
        template<> struct pi_value< long double > { long double operator()() const { return 3.1415927; } };

        /*
        // For expensive constructions, maybe this is an option:
        template<> struct pi_value< RWDecimal< RWMP3Int > > {
        const RWDecimal< RWMP3Int >& operator()() const {
        static const RWDecimal< RWMP3Int > value( "3.1415926535897932384626433832" );
        return value;
        }
        };
        */

        // Here's the single line to create a useful interface
        struct pi_t : constant< pi_t, pi_value > {} pi;

        // Another one:
        template< typename T > struct pi2_value;
        template<> struct pi2_value< float > { float operator()() const { return 9.87; } };
        template<> struct pi2_value< double > { double operator()() const { return 9.8696; } };
        template<> struct pi2_value< long double > { long double operator()() const { return 9.8696044; } };
        struct pi2_t : constant< pi2_t, pi2_value > {} pi2;

        // And their relationship:
        pi2_t operator*( const pi_t&, const pi_t& ) { return pi2_t(); }

        // Some obvious (?) constants:
#define CONSTANT_VALUE( name, value ) \
    template< typename T > struct name##_value { T operator()() const { return value; } }; \
    struct name##_t : constant< name##_t, name##_value > {} name;

        CONSTANT_VALUE( minus_one, -1 );
        CONSTANT_VALUE( zero, 0 );
        CONSTANT_VALUE( one, 1 );
        CONSTANT_VALUE( two, 2 );
        CONSTANT_VALUE( three, 3 );
        CONSTANT_VALUE( ten, 10 );
#undef CONSTANT_VALUE

        // Another one:
        template< typename T > struct sqrt2_value;
        template<> struct sqrt2_value< float > { float operator()() const { return 1.4142; } };
        template<> struct sqrt2_value< double > { double operator()() const { return 1.41421356; } };
        template<> struct sqrt2_value< long double > { long double operator()() const { return 1.4142135623730950488016887242096980785697L; } };

        // Note that the actual 'sqrt2' is not needed!
        struct sqrt2_t : constant< sqrt2_t, sqrt2_value > {} sqrt2;

        // An example to solve the naming dilemma, this time providing 'sqrt( two )'
        template< typename T > T sqrt( const T& v ) { return std::sqrt( v ); }
        sqrt2_t sqrt( const two_t& ) { return sqrt2_t(); }
    }
}

int main()
{
    // Usage example:
    using namespace boost::math;

    const float f = 1.;
    const double d = 1.;
    const long double ld = 1.;

    cout << pi * f * f << endl;
    cout << pi * d * d << endl;
    cout << pi * ld * ld << endl;

    cout << static_cast< double >( pi ) << endl;
    cout << static_cast< float >( pi ) * d * d << endl;

    cout << pi * pi * f << endl;
    cout << pi * pi * d << endl;
    cout << pi * pi * ld << endl;

    cout << pi + 2. << endl;
    cout << 2. + pi << endl;

    cout << sqrt( two ) * sqrt( 2.F ) << endl;
    cout << sqrt( two ) * sqrt( 2.L )  << endl;
}