|
Boost Users : |
From: Eric Ford (eford_at_[hidden])
Date: 2001-10-03 13:35:43
--- In Boost-Users_at_y..., Jens Maurer <Jens.Maurer_at_g...> wrote:
> Eric Ford wrote:
> > I want to require functions that take the derived type as an
> > argument. So I declare a variable of the derived at struct level
in
> > the concept class, but then g++ (2.95) complains about it being an
> > invalid use of undefined type... forward declaration... . Is
there a
> > way to make this work? If so, does anyone have/know of an example
I
> > can see how to order things to make it work?
>
> Please show us complete source code of what you want to achieve,
> plus the exact error messages gcc produces. People may want to
check
> if different compilers yield other error messages.
Ok. I tried to trim some of the fat to ease study, but don't have
time to reduce it to the simplest example. I did put it all in one
file for easy testing. If you comment out the #define
CAUSE_GCC_FAILURE, then it works for me.
#include<cmath>
#include<cstdio>
#include<utility>
#include<iostream>
#include<boost/cast.hpp>
#include<boost/operators.hpp>
#include<boost/concept_check.hpp>
#define CAUSE_GCC_FAILURE
template<class T>
struct ArithmeticConcept
{
void constraints()
{
boost::function_requires<boost::AssignableConcept<T> >();
boost::function_requires<boost::EqualityComparableConcept<T> >();
boost::function_requires<boost::ComparableConcept<T> >();
boost::function_requires<boost::PlusOpConcept<T,T,T> >();
boost::function_requires<boost::SubtractOpConcept<T,T,T> >();
boost::function_requires<boost::TimesOpConcept<T,T,T> >();
boost::function_requires<boost::DivideOpConcept<T,T,T> >();
};
};
template<class ScaledLeafClass, class UnscaledT > class
scaled_num;
// This seems to have problems with the Curiously Recursive
Template Technique / Barton-Nackman Trick
template<class T1, class T2>
struct scaling_leaf_class_concept
{
typedef T1 scaled_type;
typedef T2 unscaled_type;
typedef bool sign_type;
#ifdef CAUSE_GCC_FAILURE
scaled_type scaled;
#endif
unscaled_type unscaled;
void constraints()
{
boost::function_requires<ArithmeticConcept<unscaled_type> >();
// T1::scale(unscaled_type());
// T1::unscale(scaled_type());
// scaled_type().unscale();
// scaled_type().operator();
// sign_type b4 = scaled.sign();
};
};
// base class provides default functionality
// requires access to functions scale and unscale
// might be nice if it added a test to see if there would be
domain/range problems
template<class ScaledLeafClass, class UnscaledT >
class scaled_num :
boost::addable<ScaledLeafClass>,
boost::addable<ScaledLeafClass,UnscaledT>,
boost::subtractable<ScaledLeafClass>,
boost::subtractable<ScaledLeafClass,UnscaledT>,
boost::multipliable<ScaledLeafClass>,
boost::multipliable<ScaledLeafClass,UnscaledT>,
boost::dividable<ScaledLeafClass>,
boost::dividable<ScaledLeafClass,UnscaledT>,
boost::equality_comparable<ScaledLeafClass>,
boost::equality_comparable<ScaledLeafClass,UnscaledT>,
boost::less_than_comparable<ScaledLeafClass>,
boost::less_than_comparable<ScaledLeafClass,UnscaledT>
{
public:
typedef ScaledLeafClass leaf_type;
typedef UnscaledT unscaled_type;
typedef leaf_type scaled_type;
typedef scaled_num<leaf_type,unscaled_type> self_type;
typedef bool sign_type;
BOOST_CLASS_REQUIRES2( ScaledLeafClass, UnscaledT,
scaling_leaf_class_concept );
BOOST_CLASS_REQUIRES( UnscaledT, ArithmeticConcept );
public: // for accessing leaf_type = scaled_type, ro from outside
leaf_type const& as_leaf() const { return static_cast<leaf_type
const&>(*this); }
protected: // for accessing leaf_type = scaled_type, rw
internally
leaf_type& as_leaf() { return static_cast<leaf_type&>(*this); }
public: // here's where the three functions required in leaf_type
are called
static scaled_type scale(unscaled_type x) { return
leaf_type::scale(x); };
static unscaled_type unscale( scaled_type x) { return
x.as_leaf().unscale(x); };
unscaled_type unscale() const { return
as_leaf().unscale(as_leaf()); };
public:
unscaled_type operator()() const { return unscale(); }; // this
provides explicit conversion to the unscaled type
operator unscaled_type() const { return unscale(); }; // this
provides implicit conversion to the unscaled_type, necessary for
seemlessly replacing numerical types, but somewhat dangerous
// operators // operators for the default dumb way to do things
leaf_type& operator=(const leaf_type& a) { this->as_leaf() =
a.as_leaf(); return as_leaf(); };
leaf_type& operator-() { *this = scale(-unscale()); return
this; };
leaf_type& operator+=(const leaf_type& a) { *this =
scale(unscale()+a.unscale()); return as_leaf(); };
leaf_type& operator-=(const leaf_type& a) { *this =
scale(unscale()-a.unscale()); return as_leaf(); };
leaf_type& operator*=(const leaf_type& a) { *this =
scale(unscale()*a.unscale()); return as_leaf(); };
leaf_type& operator/=(const leaf_type& a) { *this =
scale(unscale()/a.unscale()); return as_leaf(); };
leaf_type& operator+=(const unscaled_type& a) { *this =
scale(unscale()+a); return as_leaf(); };
leaf_type& operator-=(const unscaled_type& a) { *this =
scale(unscale()-a); return as_leaf(); };
leaf_type& operator*=(const unscaled_type& a) { *this =
scale(unscale()*a); return as_leaf(); };
leaf_type& operator/=(const unscaled_type& a) { *this =
scale(unscale()/a); return as_leaf(); };
sign_type sign() const { return (operator()()<0); };
bool operator==(const leaf_type& a) const {
return(unscale()==a.unscale()); };
bool operator<(const leaf_type& a) const {
return(unscale()<a.unscale()); };
bool operator==(const unscaled_type& a) { return(unscale()==a);
};
bool operator<(const unscaled_type& a) { return(unscale()<a); };
bool operator>(const unscaled_type& a) { return(unscale()>a); };
};
template<class T1,class T2>
inline ostream& operator<<(ostream& os, scaled_num<T1,T2> const&
x)
{ return (os << x()); }
// Concept for tags: Specify base and types
template<class T>
struct log_base_tag_concept
{
typename T::internal_type s;
typename T::return_type u;
typename T::log_base_type b;
typename T::sign_type sign;
void constraints()
{
boost::function_requires<ArithmeticConcept<typename T::return_type>
>();
BOOST_STATIC_ASSERT(T::Base>0);
b = T::Base;
s = T::scale_helper(u);
u = T::unscale_helper(s);
};
};
template<class T>
struct log_e_tag
{
typedef T return_type;
typedef T internal_type;
typedef T log_base_type;
typedef bool sign_type;
BOOST_STATIC_CONSTANT(log_base_type, Base = M_E);
static internal_type scale_helper(const T& x) { return
std::log(x); };
static T unscale_helper(const internal_type& x) { return
std::exp(x); };
};
// Example of one scaling function that could be used...
template<class UnscaledType, class TraitsT =
log_e_tag<UnscaledType> > class log_num;
template<class UnscaledType, class TraitsT >
class log_num : public scaled_num< log_num<UnscaledType,TraitsT>,
UnscaledType >
{
BOOST_CLASS_REQUIRES( UnscaledType, ArithmeticConcept );
BOOST_CLASS_REQUIRES(TraitsT, log_base_tag_concept);
public: // typedefs
typedef TraitsT traits;
typedef log_num<UnscaledType,traits > self_type;
typedef scaled_num< self_type, UnscaledType > base_type;
typedef typename traits::sign_type sign_type;
typedef typename traits::internal_type internal_type;
public: // constructors
explicit log_num(unscaled_type Value) :
mValue(scale_internal(abs(Value))), mSign(Value<0) {}; // from
unscaled
log_num(internal_type Value, sign_type Sign ) : mValue(Value),
mSign(Sign) {}; // from scaled
protected: // data (internal, I should hope it has some data)
internal_type mValue;
sign_type mSign; // true = negative, false = positive
protected: // scaling function helpers (optional, but generally
helpful)
static internal_type scale_internal(const unscaled_type&
x)
{ return traits::scale_helper(x); };
static unscaled_type unscale_internal(const internal_type&
x)
{ return traits::unscale_helper(x); };
template<class T1, class T2>
bool log_num_xor(const T1& a, const T2& b){ return
((a)&&(!b))||((!a)&&(b)); }
public: // data inspectors (optional, but generally desired)
const internal_type& get_scaled_value() const { return mValue;
};
sign_type get_sign() const { return mSign; };
typename TraitsT::log_base_type get_base() const { return
TraitsT::Base; };
protected: // data mutators (internal, optional)
const internal_type& scaled_value() const { return mValue; };
internal_type& scaled_value() { return mValue; };
sign_type sign() const { return mSign; };
sign_type& sign() { return mSign; };
public: // scaling functions (REQUIRED)
static scaled_type scale(unscaled_type x) { return
self_type(x); };
static unscaled_type unscale(const scaled_type& x)
{
if(x.sign()) return -unscale_internal(x.scaled_value());
else return unscale_internal(x.scaled_value());
};
unscaled_type unscale() const { return unscale(*this); }; //
have to provide since overloading other unscale
};
// specialize functions which can be optimized for this particular
scaling function
template<class TagT, class T >
void log_num_test(T x, T y, T z)
{
log_num<T,TagT> bnx(x);
log_num<T,TagT> bny = log_num<T,TagT>(y);
log_num<T,TagT> bnz(-1);
cout << "start: x = " << bnx << " y = " << bny << " z = "
<< bnz << endl;
bnz = bnx + bny;
cout << "z=x+y: x = " << bnx << " y = " << bny << " z = "
<< bnz << endl;
bnz = bnx * bny;
cout << "z=x*y: x = " << bnx << " y = " << bny << " z = "
<< bnz << endl;
bnz = bnx;
cout << "z=x: x = " << bnx << " y = " << bny << " z = "
<< bnz << endl;
cout << "z==/</>x: " << (bnz==bnx) << " " << (bnz<bnx) << " " <<
(bnz>bnx) << endl;
bnz *= bnx;
cout << "z*=x: x = " << bnx << " y = " << bny << " z = "
<< bnz << endl;
cout << "z==/</>x: " << (bnz==bnx) << " " << (bnz<bnx) << " " <<
(bnz>bnx) << endl;
bnz *= x;
cout << "z*=x: x = " << bnx << " y = " << bny << " z = "
<< bnz << endl;
};
int main(int argc, char **argv)
{
float x = 0.5, y=18.;
if(argc>1) { sscanf(argv[1],"%f",&x); }
if(argc>2) { sscanf(argv[2],"%f",&y); }
cout << "float, log_e" << endl;
log_num_test<log_e_tag<float>,float>(x,y,-1);
return 0;
}
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net