A mess with inheritance, virtual classes , and templates.

C

cesarth

Hello all,

I have a code that works without templating and when I apply templates
doesn't.
I tried to simplify it as much as possible, but it is a little long.

This code works without templating:

//*****************************************************************
#include <iostream>
#include <cmath> // exp

using namespace std;

struct basf{
virtual double eval(void) const{ cerr << "ERROR: base
class()"<<endl; };
};
ostream& operator<<(ostream &os, const basf & bas){ os<< bas.eval();
return os; };

struct vfoo: public basf{
double * var;
vfoo( double * v, const string &rep1 ): var(v), rep(rep1){};
void operator=( const double & v ) { *var=v; };
// operator foo( ){ foo fun(this); return fun; };
// operator foo&( ){ foo fun(this); return fun; };
double eval() const{ return *var; };
};
struct foo{
basf *fp;
foo( basf * pbfun ) : fp(pbfun) { };
foo( vfoo &vx ) : fp(&vx) { };
// foo( ) { };
double eval(void) const{ return fp->eval(); };
};

struct efoo: public basf{
foo sub;
efoo( foo sf ) : sub(sf) {};
operator foo( ){ foo fun(this); return fun; };
double eval() const{ return exp( sub.eval() ); };
};

efoo exp3( foo sf ) { return efoo( sf ); };

void testfun2(void){
double x=14.10;
vfoo vx(&x,"x");
cout << "vx = " << vx << endl;
foo f1=vx;
cout <<" f1.eval() = "<< f1.eval() << endl;
foo f2= efoo(vx);
cout <<" f2.eval() = "<< f2.eval() << endl;
foo f3= exp3(f1);
cout <<" f3.eval() = "<< f3.eval() << endl;
}
int main( int argc, char** argv, char** envp){
testfun2();
return 0;
}
//*****************************************************************

But doesn't with templates:

//*****************************************************************
#include <iostream>
#include <cmath> // exp

using namespace std;

template <class T> struct basf{
virtual T eval(void) const{ cerr << "ERROR: base class()"<<endl; };
};
template<class T> ostream& operator<<(ostream &os, const basf<T> & bas)
{ os<< bas.eval(); return os; };

template <class T> struct vfoo: public basf<T>{
T * var;
vfoo( T * v, const string &rep1 ): var(v), rep(rep1){};
void operator=( const T & v ) { *var=v; };
// operator foo<T>( ){ foo<T> fun(this); return fun; };
// operator foo<T>&( ){ foo<T> fun(this); return fun; };
T eval() const{ return *var; };
};
template <class T> struct foo{
basf<T> *fp;
foo( basf<T> * pbfun ) : fp(pbfun) { };
foo( vfoo<T> &vx ) : fp(&vx) { };
// foo( ) { };
T eval(void) const{ return fp->eval(); };
};
template <class T> struct efoo: public basf<T>{
foo<T> sub;
efoo( foo<T> sf ) : sub(sf) {};
operator foo<T>( ){ foo<T> fun(this); return fun; };
T eval() const{ return exp( sub.eval() ); };
string str(void) const { return "exp("; };
};

template <class T> efoo<T> exp3( foo<T> sf ) { return
efoo<T>( sf ); };

void testfun2(void){
double x=14.10;
vfoo<double> vx(&x,"x");
cout << "vx = " << vx << endl;
foo<double> f1=vx;
cout <<" f1.eval() = "<< f1.eval() << endl;
foo<double> f2= efoo<double>(vx);
cout <<" f2.eval() = "<< f2.eval() << endl;
foo<double> f3= exp3(vx);
cout <<" f3.eval() = "<< f3.eval() << endl;
}
int main( int argc, char** argv, char** envp){
testfun2();
return 0;
}

//*****************************************************************

The error it gives (with gcc version 4.4.5) is

foo4.cpp: In function ‘void testfun2()’:
foo4.cpp:45: error: no matching function for call to
‘exp3(vfoo<double>&)’

The question is ¿Why doesn't detect de conversion vfoo -> foo?, as you
see commented,
I tried to place vfoo after foo and doing the conversion in vfoo
instead of foo, but
that didn't work either.

¿How could I solve the problem? . My aim is to be able to write
exp3(vx) without having to do a cast or conversion in testfun2. I know
that I could write a overloaded function exp3
whose argument would be a vfoo, that I find that clumsy if I derive a
lot of classes from basf like vfoo.

Thanks in advance,

César.
 
C

cesarth

Hello again, where in the non-template version I write "f3= exp3(f1)"
I meant "f3= exp3(vx)".
The problem is still there.

César
 
V

Victor Bazarov

I have a code that works without templating and when I apply templates
doesn't.
I tried to simplify it as much as possible, but it is a little long.

This code works without templating[..]

But doesn't with templates:

//*****************************************************************
#include<iostream>
#include<cmath> // exp

using namespace std;

template<class T> struct basf{
virtual T eval(void) const{ cerr<< "ERROR: base class()"<<endl; };
};
template<class T> ostream& operator<<(ostream&os, const basf<T> & bas)
{ os<< bas.eval(); return os; };

template<class T> struct vfoo: public basf<T>{
T * var;
vfoo( T * v, const string&rep1 ): var(v), rep(rep1){};
void operator=( const T& v ) { *var=v; };
// operator foo<T>( ){ foo<T> fun(this); return fun; };
// operator foo<T>&( ){ foo<T> fun(this); return fun; };
T eval() const{ return *var; };
};
template<class T> struct foo{
basf<T> *fp;
foo( basf<T> * pbfun ) : fp(pbfun) { };
foo( vfoo<T> &vx ) : fp(&vx) { };
// foo( ) { };
T eval(void) const{ return fp->eval(); };
};
template<class T> struct efoo: public basf<T>{
foo<T> sub;
efoo( foo<T> sf ) : sub(sf) {};
operator foo<T>( ){ foo<T> fun(this); return fun; };
T eval() const{ return exp( sub.eval() ); };
string str(void) const { return "exp("; };
};

template<class T> efoo<T> exp3( foo<T> sf ) { return
efoo<T>( sf ); };

void testfun2(void){
double x=14.10;
vfoo<double> vx(&x,"x");
cout<< "vx = "<< vx<< endl;
foo<double> f1=vx;
cout<<" f1.eval() ="<< f1.eval()<< endl;
foo<double> f2= efoo<double>(vx);
cout<<" f2.eval() ="<< f2.eval()<< endl;
foo<double> f3= exp3(vx);

So, the template argument for 'exp3' needs to be determined from this
call, right? 'vx' is a 'vfoo<double>', right? There is no 'exp3'
function that takes 'vfoo' template instance as its argument. There is,
however, 'exp3' that takes a 'foo' template instance. That is where it
breaks down. Trying to find what template argument to instantiate the
'exp3' with, the compiler cannot come up with any because there is no
suitable 'exp3'.

The main difference between that and looking for a suitable function to
call among some overloaded functions is that the latter *allows
conversions* for arguments. Matching template arguments to determine
what template to instantiate or what the template argument is going to
be, *requires perfect match* from a list of "deducible contexts" and no
conversions are considered.
cout<<" f3.eval() ="<< f3.eval()<< endl;
}
int main( int argc, char** argv, char** envp){
testfun2();
return 0;
}

//*****************************************************************

The error it gives (with gcc version 4.4.5) is

foo4.cpp: In function ‘void testfun2()’:
foo4.cpp:45: error: no matching function for call to
‘exp3(vfoo<double>&)’

The question is ¿Why doesn't detect de conversion vfoo -> foo?, as you
see commented,

Because that's prohibited by the Standard for the purposes of template
argument deduction.
I tried to place vfoo after foo and doing the conversion in vfoo
instead of foo, but
that didn't work either.

No conversions are considered for the purposes of deducing template
arguments.
¿How could I solve the problem? . My aim is to be able to write
exp3(vx) without having to do a cast or conversion in testfun2. I know
that I could write a overloaded function exp3
whose argument would be a vfoo, that I find that clumsy if I derive a
lot of classes from basf like vfoo.

I am not sure what you call "the problem". You haven't followed the
rules of the language. You want to break the rules, and that's an
unsolvable problem, methinks. It's similar to some folks' statements
like "I want to overload operator ** to be exponentiation". Well,
you're not allowed to make up your own syntax, we tell them.

You can call your 'exp3' with the explicit template argument after it.
You don't seem to want that. You can overload 'exp3' with 'vfoo'
template as its argument, but you don't seem to want that either. Well,
decide what you want, what you can live with, and then use that.

There is probably a convoluted way to go around the limitation of the
language that you've hit, but it's all going to be "clumsy", I suppose.

V
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top