Boost logo

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