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
--- In Boost-Users@y..., Jens Maurer wrote:
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
#include
#include
#define CAUSE_GCC_FAILURE
template<class T>
struct ArithmeticConcept
{
void constraints()
{
boost::function_requires();
boost::function_requires();
boost::function_requires();
boost::function_requires >();
boost::function_requires >();
boost::function_requires >();
boost::function_requires >();
};
};
template class
scaled_num;
// This seems to have problems with the Curiously Recursive
Template Technique / Barton-Nackman Trick
template
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 >();
// 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 scaled_num :
boost::addable<ScaledLeafClass>,
boost::addable,
boost::subtractable<ScaledLeafClass>,
boost::subtractable,
boost::multipliable<ScaledLeafClass>,
boost::multipliable,
boost::dividable<ScaledLeafClass>,
boost::dividable,
boost::equality_comparable<ScaledLeafClass>,
boost::equality_comparable,
boost::less_than_comparable<ScaledLeafClass>,
boost::less_than_comparable
{
public:
typedef ScaledLeafClass leaf_type;
typedef UnscaledT unscaled_type;
typedef leaf_type scaled_type;
typedef scaled_num 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(*this); }
protected: // for accessing leaf_type = scaled_type, rw
internally
leaf_type& as_leaf() { return static_cast(*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()(const unscaled_type& a) { return(unscale()>a); };
};
template
inline ostream& operator<<(ostream& os, scaled_num 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
();
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 log_num;
template
class log_num : public scaled_num< log_num,
UnscaledType >
{
BOOST_CLASS_REQUIRES( UnscaledType, ArithmeticConcept );
BOOST_CLASS_REQUIRES(TraitsT, log_base_tag_concept);
public: // typedefs
typedef TraitsT traits;
typedef log_num 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
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
void log_num_test(T x, T y, T z)
{
log_num bnx(x);
log_num bny = log_num(y);
log_num 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) << " " << (bnzbnx) << endl;
bnz *= bnx;
cout << "z*=x: x = " << bnx << " y = " << bny << " z = "
<< bnz << endl;
cout << "z==/>x: " << (bnz==bnx) << " " << (bnzbnx) << 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(x,y,-1);
return 0;
}