#include #include 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; }