//#define MACRO
//#define VARIABLE
//#define FUNCTION
#define TEMPLATE

#ifdef MACRO

#define pi_f 3.14
#define pi_d 3.1416
#define pi_ld 3.1415927

#else
#ifdef VARIABLE

const float pi_f = 3.14;
const double pi_d = 3.1416;
const long double pi_ld = 3.1415927;

#else
#ifdef FUNCTION

inline float pi_f_func() { return 3.14; }
inline double pi_d_func() { return 3.1416; }
inline long double pi_ld_func() { return 3.1415927; }

#define pi_f pi_f_func()
#define pi_d pi_d_func()
#define pi_ld pi_ld_func()

#else

template< class T, template< typename > class F > struct constant
{
    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
};

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

struct pi_t : constant< pi_t, pi_value > {} pi;

#define pi_f pi
#define pi_d pi
#define pi_ld pi

#endif
#endif
#endif

int main()
{
    float f = 1.;
    double d = 1.;
    long double ld = 1.;

    for( int i = 0; i < 100000000; ++i ) {
        f += pi_f;
        d += pi_d;
        ld += pi_ld;
    }

    if( f == 0 || d == 0 || ld == 0 )
        return 1;
}

