473,329 Members | 1,261 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,329 software developers and data experts.

Templated virtual member functions

Hello,

templated virtual member functions are not allowed. Now I am searching
for a good workaround for this problem, but I can't find any.
Here's my problem:

class Base
{
template <typename T>
virtual void setParam(std::string s, const T& value);
};

clas Derived : public Base
{
template <typename T>
void setParam(std::string s, const T& value);
};

Base* b = new Derived;
b->setParam( "msg", 5 );

How can I make this work?

-Matthias

Feb 14 '06 #1
11 1891
Matthias wrote:
templated virtual member functions are not allowed. Now I am searching
for a good workaround for this problem, but I can't find any.
Here's my problem:

class Base
{
template <typename T>
virtual void setParam(std::string s, const T& value);
};

clas Derived : public Base
{
template <typename T>
void setParam(std::string s, const T& value);
};

Base* b = new Derived;
b->setParam( "msg", 5 );

How can I make this work?


By redesigning your classes. Why do you need it virtual? Why do you need
to derive from Base? Why do you need it a template? You're presenting us
with a "solution" to an unknown problem. We don't know what you're trying
to accomplish. If you explained your design intentions, somebody might be
able to recommend something.

V
--
Please remove capital As from my address when replying by mail
Feb 14 '06 #2
class Base
{
template <typename T>
virtual void setParam(std::string s, const T& value);
};
and what size do you propose the v-table should be?
clas Derived : public Base
{
template <typename T>
void setParam(std::string s, const T& value);
};

Base* b = new Derived;
b->setParam( "msg", 5 );

How can I make this work?


You could ask how come ostream classes can stream in lots of different
types but yet streaming is a non-virtual function.

Where is the polymorphism? What will happen in different versions of
Base?

With ostream they all do something common - effectively convert the
type to a string then have different ways of writing the string.

Feb 14 '06 #3
You can use the TypeList structure
Feb 14 '06 #4
Matthias wrote:
Hello,

templated virtual member functions are not allowed. Now I am searching
for a good workaround for this problem, but I can't find any.
Here's my problem:

class Base
{
template <typename T>
virtual void setParam(std::string s, const T& value);
};

clas Derived : public Base
{
template <typename T>
void setParam(std::string s, const T& value);
};

Base* b = new Derived;
b->setParam( "msg", 5 );

How can I make this work?

-Matthias


What you want can be done with a bit of a trick. The idea is to build up
runtime information by compile time.

#include <typeinfo> // RTTI
#include <memory> // auto_ptr

class objectwrapper_base // runtime support for type query
{
public:
virtual const void* query_object(std::type_info) const = 0;
virtual ~objectwrapper_base(){}
};

template <typename T> // compile time type information build up
class objectwrapper: public objectwrapper_base
{
const T* ptr;

public:
objectwrapper(const T& t){ptr = &t;}

const void* query_object(std::type_info ti) const{
if (ti == typeid(T))
return static_cast<const void*>(ptr);

return 0;
}
};

class envelop // a simple class to wrap the above up into one
{
std::auto_ptr<
objectwrapper_base> wrapper;

public:
template <typename T>
envelop(const T& obj):
wrapper(new objectwrapper<T>(obj))
{}

template <typename T> // just a wrapper function
const T* query_object(void) const{
return static_cast<const T*>(
wrapper->query_object(typeid(T)));
}
};
// and for your problem, we just use class envelop
// to achieve the template effect

class Base
{
public:
virtual void setParam(std::string s, envelop elp);
};

class Derived : public Base
{
public:
void setParam(std::string s, envelop elp);
};
For production code you may consider boost::any to be a much polished
alternative.

Regards,
Ben
Feb 15 '06 #5
I am sorry for the very late reply.

My problem: Basically I have different implementations of so called
"effect files". I should be able to set parameters of an arbitrary type
in them (via the setParam function). For example one implementation has
a Python backend. The python backend can take almost any c++ object and
passes it to the python side (I wrap my application with swig if that
helps you). Other implementations of effect files should also be able
to the same. That's why I wanted to put this into an interface-like
base class so that I can set params to an effect file, no matter which
implementation is working behind the scenes. Creating lots of overloads
for every possible type is not an option here.

Feb 25 '06 #6
This looks like a compile time version of dynamic_cast.
The problem here is that I need to pass elp into another templated
function. This means I would need to do something like this in the
Derived implementation:

setParam(std::string s, envelop elp)
{
createPythonObject( elp.query_object() );

This won't compile because I have to do something like
createPythonObject( elp.query_object<Type>() ); The createPythonObject
template has lots of different specializations depending on the type of
the class that was wrapped by elp.

Feb 25 '06 #7
Matthias wrote:
This looks like a compile time version of dynamic_cast.
The problem here is that I need to pass elp into another templated
function. This means I would need to do something like this in the
Derived implementation:

setParam(std::string s, envelop elp)
{
createPythonObject( elp.query_object() );

This won't compile because I have to do something like
createPythonObject( elp.query_object<Type>() ); The createPythonObject
template has lots of different specializations depending on the type of
the class that was wrapped by elp.


Ok, here's the trick: bring every essential operation up to
objectwrapper_base class. For example:

class objectwrapper_base // runtime support for type query
{
public:
virtual const void* query_object(std::type_info) const = 0;
virtual ~objectwrapper_base(){}

// the following member function is newly added:
virtual void createPythonObject(void);
};

Now in the corresponding objectwrapper template, implement the member:

template <typename T> // compile time type information build up
class objectwrapper: public objectwrapper_base
{
const T* ptr;

public:
objectwrapper(const T& t){ptr = &t;}

const void* query_object(std::type_info ti) const{
if (ti == typeid(T))
return static_cast<const void*>(ptr);

return 0;
}

// newly implemented function:
void createPythonObject(void){
::createPythonObject(*ptr);
}
};

Finally, you need to wrap these in the envelop class:

class envelop // a simple class to wrap the above up into one
{
std::auto_ptr<
objectwrapper_base> wrapper;

public:
template <typename T>
envelop(const T& obj):
wrapper(new objectwrapper<T>(obj))
{}

template <typename T> // just a wrapper function
const T* query_object(void) const{
return static_cast<const T*>(
wrapper->query_object(typeid(T)));
}

// newly added function
void createPythonObject(void){
wrapper->createPythonObject();
}
};

Now all you need in SetParam is hence:

setParam(std::string s, envelop elp){
// createPythonObject( elp.query_object() );
elp.createPythonObject();
// ...
}

Regards,
Ben
Feb 25 '06 #8
Hmmm, I see a problem with this approach. If I understand your
proposal properly, I go like this:

class Base
{
virtual
void setParam(string s, envelop elp) = 0;
};

class Derived1
{
void setParam(string s, envelop elp)
{
elp.createPythonObject();
}
};

class Derived2
{
void setParam(string s, envelop elp)
{
elp.doSomethingElse();
}
};

This means, whenever I add/remove/change a derived class, my elp class
also needs to change. This seems to violate encapsulation (derived
classes can use methods from other derived classes) and makes it
impossible to use libraries (think if envelop is compiled into one
lib, somebody wants to create another derived class but can't modify
envelop anymore...)

I can't find a good solution to this problem. Maybe it's not easily
possible in C++. All I want to tell it is to have a base class which
requires derived classes to implement a certain template.

I can see the problem about the vtable, but maybe there are workarounds
like benben posted. Maybe I am thinking weird, but sometimes I have the
slight feeling C++ doesn't adapt well to human patterns of thinking and
ideas of implementation.

-Matthias

Feb 28 '06 #9
Matthias wrote:
Hmmm, I see a problem with this approach. If I understand your
proposal properly, I go like this:

class Base
{
virtual
void setParam(string s, envelop elp) = 0;
};

class Derived1
I think you mean class Derived1: public Base
{
void setParam(string s, envelop elp)
{
elp.createPythonObject();
}
};

class Derived2
// :public Base
{
void setParam(string s, envelop elp)
{
elp.doSomethingElse();
}
};
Basically, yes.

This means, whenever I add/remove/change a derived class, my elp class
also needs to change. This seems to violate encapsulation (derived
classes can use methods from other derived classes) and makes it
impossible to use libraries (think if envelop is compiled into one
lib, somebody wants to create another derived class but can't modify
envelop anymore...)

I can't find a good solution to this problem. Maybe it's not easily
possible in C++. All I want to tell it is to have a base class which
requires derived classes to implement a certain template.
You had the solution -- the envelop class. In fact, it is very similar
to what a script interpreter will do with variables.

Perhaps I gave you a wrong example of how to use the envelop class,
perhaps you are trying to abstract at the wrong spot. A supposed way of
using an envelop through casting:

if (int* pi = elp.retrieve<int>())
createPythonObject<int>(*pi);
else if (string* ps = elp.retrieve<string>())
createPythonObject<string>(*ps);
// etc

Note the finite set of types you can deal with. But I suspect how much
createPythonObject template can deal with any type.

I can see the problem about the vtable, but maybe there are workarounds
like benben posted. Maybe I am thinking weird, but sometimes I have the
slight feeling C++ doesn't adapt well to human patterns of thinking and
ideas of implementation.
Perhaps you should just tell us why you want to do sub-typing and
subsequently have to resolve to using virtual functions. It seems that
you problem can very simply overcome by not using virtual functions at all.

-Matthias


Ben
Feb 28 '06 #10
First of all, thanks for looking into this even more.

I see that I can query for each type manually, but then I could just go
without the envelop class and write a virtual function for every type.
createPythonObject can deal with almost any type that I use in my
program, including complex classes.

I'll try to re-explain what I am trying to achieve:

There's a so called effect-file which you can simply think of as a
parameter collection for now. It will take parameters of different
types and do something with them. Now there is probably more than one
effect-file implementation. Each implementation does different things
with the parameters passed to it. For example I mentioned the python
implementation which creates python objects of the passed variables.
There might be another implementation creating Perl objects or even a
C++ implementation which stores the variables into std::maps (one for
each type).
The caller should not have to care which implementation he is using,
that's why there's an abstract base class.
Like

void DoSomething(Base* b)
{
b->SetParameter("bla", 11);
}

Base* b = new Derived1;
DoSomething(b);
delete b;

b = new Derived2;
DoSomething(b);
delete b;

The user should be able to call setParameter on b for a whole bunch of
types. If a type is not supported by the underlying implementation then
the compiler should barf, otherwise it should compile.

Does this make sense?

I thought about replacing the virtual functions somehow with templates,
but didn't come up with anything that makes sense.

Thanks again for your kind help!

-Matthias

Feb 28 '06 #11
> void DoSomething(Base* b)
{
b->SetParameter("bla", 11);
}
Ok, I roughly see what your problem is. I still don't get why you need
to use an abstract base, wouldn't the following just do the trick?

template <typename EffectFileImplT>
void DoSomething(EffectFileImplT& ef)
{
ef.SetParameter("bla", 11); // non-virtual call
}

Base* b = new Derived1;
DoSomething(b);
delete b;

b = new Derived2;
DoSomething(b);
delete b;


Effect1 ef1; // non-polymorphic type
DoSometing(ef1);

Effect2 ef2; // non-polymorphic type
DoSomething(ef2);
Ben
Feb 28 '06 #12

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: tirath | last post by:
Hi all, I have a templated class that derives from a non-templated abstract class. How do I then cast a base class pointer to a <templated> derived class pointer in a generalised fashion? ...
18
by: nenad | last post by:
Wouldn't it be nice if we could do something like this: class Funky{ public: auto virtual void doStuff(){ // dostuff } };
2
by: Thomas Matthews | last post by:
Hi, I would like to create a table (or vector) of pointers to templated functions. 1. How do I declare a typedef of a pointer to a templated function? For example, I have some functions...
9
by: Jon Wilson | last post by:
I have a class which needs to accumulate data. The way we get this data is by calling a member function which returns float on a number of different objects of different type (they are all the...
11
by: santosh | last post by:
Hello, I was going through the Marshal Cline's C++ FAQ-Lite. I have a doubt regarding section 33.10. Here he is declaring a pure virtual destructor in the base class. And again defining...
6
by: Dan Huantes | last post by:
I was presented a problem today where a class had member variable that was an object of a templated class. The class wanted to instantiate the object as a private member variable and call a...
2
by: Amadeus W. M. | last post by:
I have a bunch of templated functions: template <class Type_t> double f2(Type_t x) { return 2*x; } template <class Type_t> double f3(Type_t x) { return 3*x; }
7
by: eric | last post by:
hello i'm confused by an example in the book "Effective C++ Third Edition" and would be grateful for some help. here's the code: class Person { public: Person(); virtual ~Person(); // see...
2
by: domehead100 | last post by:
I have a templated class, CDerived: template <typename TValue, typename TDraw, typename TEdit ...> class CDerived : public CBase { TValue m_Value public: TValue& GetValue() const {
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
1
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.