is it possible to create the functionality of a virtual template method?

T

ted orange

I would like to have a container of objects where each object has a template
method like so



template <class T>

void DoSomething(T& t);



so that I may, at runtime, pass various types to that method. The type will
be automatically dededuced.



I understand that virtual template methods are not permitted and that
containers may only store heterogeneous collections if they are polymorphic.



Is there a mechanism by which I can attain my objective?



Thanks.
 
M

Michael Doubez

I would like to have a container of objects where each object has a template
method like so

template <class T>

void DoSomething(T& t);

so that I may, at runtime, pass various types to that method. The type will
be automatically dededuced.

I understand that virtual template methods are not permitted and that
containers may only store heterogeneous collections if they are polymorphic.

Is there a mechanism by which I can attain my objective?

There are many ways with different trade-offs. It depends on the
contract you can make on T or on how much you can impact on the
objects.

Three examples:
1 You could use visitor pattern on your collection; that way you
could pass virtually any type T. But it comes with high costs in terms
of coupling.
2 You can wrap T into a polymorphic object reflecting the contracts/
concepts on T and pass it to a virtual function. It comes at the cost
of reducing the range of type.
3 You could use double dispatch. The costs are doubled :)

Myself, I would favor the second solution because it provides high
control on the input types and keeps coupling low.
 
T

ted orange

I would like to have a container of objects where each object has a
template
method like so

template <class T>

void DoSomething(T& t);

so that I may, at runtime, pass various types to that method. The type
will
be automatically dededuced.

I understand that virtual template methods are not permitted and that
containers may only store heterogeneous collections if they are
polymorphic.

Is there a mechanism by which I can attain my objective?

There are many ways with different trade-offs. It depends on the
contract you can make on T or on how much you can impact on the
objects.

Three examples:
1 You could use visitor pattern on your collection; that way you
could pass virtually any type T. But it comes with high costs in terms
of coupling.
2 You can wrap T into a polymorphic object reflecting the contracts/
concepts on T and pass it to a virtual function. It comes at the cost
of reducing the range of type.
3 You could use double dispatch. The costs are doubled :)

Myself, I would favor the second solution because it provides high
control on the input types and keeps coupling low.

--
Michael

Hi Michael,

I think I understand what you're saying but plz provide an example of 2 to
clarify. Thanks.
 
M

Michael Doubez

I would like to have a container of objects where each object has a
template
method like so
template <class T>
void DoSomething(T& t);
so that I may, at runtime, pass various types to that method. The type
will
be automatically dededuced.
I understand that virtual template methods are not permitted and that
containers may only store heterogeneous collections if they are
polymorphic.
Is there a mechanism by which I can attain my objective?

There are many ways with different trade-offs. It depends on the
contract you can make on T or on how much you can impact on the
objects.

Three examples: [snip]
  2 You can wrap T into a polymorphic object reflecting the contracts/
concepts on T and pass it to a virtual function. It comes at the cost
of reducing the range of type. [snip]
Myself, I would favor the second solution because it provides high
control on the input types and keeps coupling low.
[snip]
I think I understand what you're saying but plz provide an example of 2 to
clarify. Thanks.

I have posted an example not so long ago:
http://groups.google.fr/group/comp.lang.c++/browse_frm/thread/724c2ca96069a245/544fa4fb6b567799

Here is a copy of the relevant example:
<quote>
One approach is to use dynamic polymorphism, that is if you can
define a same contract on your type. As an example if your foo is only
displaying a message with the data in parameter, your contract if that
the type should support (ostream<<T), you define the interface:

struct foo_ostreamable
{
virtual ostream& output(ostream&)const=0;

};

Then you define a templated foo_streambable implementation:

template<typename T>
struct foo_ostreamable_imp: foo_ostreamable
{
T value;
foo_ostreamable_imp(const T& t):value(t){}

virtual ostream& output(ostream& os)const{return os<<value;}

};

And finally the parameter of SuperClass::foo with templated
constructor:

struct foo_param
{
template<typename T>
foo_param(const T& t){data.reset(new foo_ostreamable_imp<T>(t));

scoped_ptr<foo_ostreamable> data;

};

// foo_param can be written into ostream
ostream& operator<<(ostream& os,const foo_param& p)
{
return p.data->output(os);

}

And finally, you define your classes:
class SuperClass
{
public:
virtual void foo(const foo_param&) const = 0;

};

class SubClass: public SuperClass
{
public:
virtual void foo(const foo_param& p) const { cout << p <<
endl;}

} ;

The compiler will automatically resolve with correct subtype:
SubClass s;
s.foo(1);
s.foo(0.1);
s.foo("bar");
....

If you want to keep/compare foo_param values, there is some management
to do such as deep copy and others to put it into canonical form. If a
type doesn't react as you want, you overload foo_param constructor.
</quote>
 
T

ted orange

I would like to have a container of objects where each object has a
template
method like so
template <class T>
void DoSomething(T& t);
so that I may, at runtime, pass various types to that method. The type
will
be automatically dededuced.
I understand that virtual template methods are not permitted and that
containers may only store heterogeneous collections if they are
polymorphic.
Is there a mechanism by which I can attain my objective?

There are many ways with different trade-offs. It depends on the
contract you can make on T or on how much you can impact on the
objects.

Three examples: [snip]
2 You can wrap T into a polymorphic object reflecting the contracts/
concepts on T and pass it to a virtual function. It comes at the cost
of reducing the range of type. [snip]
Myself, I would favor the second solution because it provides high
control on the input types and keeps coupling low.
[snip]
I think I understand what you're saying but plz provide an example of 2 to
clarify. Thanks.

I have posted an example not so long ago:
http://groups.google.fr/group/comp.lang.c++/browse_frm/thread/724c2ca96069a245/544fa4fb6b567799

Here is a copy of the relevant example:
<quote>
One approach is to use dynamic polymorphism, that is if you can
define a same contract on your type. As an example if your foo is only
displaying a message with the data in parameter, your contract if that
the type should support (ostream<<T), you define the interface:

struct foo_ostreamable
{
virtual ostream& output(ostream&)const=0;

};

Then you define a templated foo_streambable implementation:

template<typename T>
struct foo_ostreamable_imp: foo_ostreamable
{
T value;
foo_ostreamable_imp(const T& t):value(t){}

virtual ostream& output(ostream& os)const{return os<<value;}

};

And finally the parameter of SuperClass::foo with templated
constructor:

struct foo_param
{
template<typename T>
foo_param(const T& t){data.reset(new foo_ostreamable_imp<T>(t));

scoped_ptr<foo_ostreamable> data;

};

// foo_param can be written into ostream
ostream& operator<<(ostream& os,const foo_param& p)
{
return p.data->output(os);

}

And finally, you define your classes:
class SuperClass
{
public:
virtual void foo(const foo_param&) const = 0;

};

class SubClass: public SuperClass
{
public:
virtual void foo(const foo_param& p) const { cout << p <<
endl;}

} ;

The compiler will automatically resolve with correct subtype:
SubClass s;
s.foo(1);
s.foo(0.1);
s.foo("bar");
....

If you want to keep/compare foo_param values, there is some management
to do such as deep copy and others to put it into canonical form. If a
type doesn't react as you want, you overload foo_param constructor.
</quote>

--
Michael

Thanks for your time Michael,

I'm a bit confused (I struggle with abstract concepts). Why is your example
different from simply using polymorphism? Like this:

class Pet
{
public:
virtual void Speak() = 0;
};

class Cat : public Pet
{
public:
void Speak(){cout << "meow";}
};

class Dog : public Pet
{
public:
void Speak(){cout << "woof";}
};


void DoSomething(const Pet& p)
{
p.Speak();
}

Is it that in your example the contract for what a type is permitted to do
is specified outside its definition?
 
M

Michael Doubez

I would like to have a container of objects where each object has a
template
method like so
template <class T>
void DoSomething(T& t);
so that I may, at runtime, pass various types to that method. The type
will
be automatically dededuced.
I understand that virtual template methods are not permitted and that
containers may only store heterogeneous collections if they are
polymorphic.
Is there a mechanism by which I can attain my objective?
There are many ways with different trade-offs. It depends on the
contract you can make on T or on how much you can impact on the
objects.
Three examples: [snip]
2 You can wrap T into a polymorphic object reflecting the contracts/
concepts on T and pass it to a virtual function. It comes at the cost
of reducing the range of type. [snip]
Myself, I would favor the second solution because it provides high
control on the input types and keeps coupling low.
[snip]
I think I understand what you're saying but plz provide an example of 2 to
clarify. Thanks.

I have posted an example not so long ago:http://groups.google.fr/group/comp.lang.c++/browse_frm/thread/724c2ca...

Here is a copy of the relevant example:
<quote>
One approach is to use dynamic polymorphism, that is if you can
define a same contract on your type. As an example if your foo is only
displaying a message with the data in parameter, your contract if that
the type should support (ostream<<T), you define the interface:

struct foo_ostreamable
{
  virtual ostream& output(ostream&)const=0;

};

Then you define a templated foo_streambable implementation:

template<typename T>
struct foo_ostreamable_imp: foo_ostreamable
{
  T value;
  foo_ostreamable_imp(const T& t):value(t){}

  virtual ostream& output(ostream& os)const{return os<<value;}

};

And finally the parameter of SuperClass::foo with templated
constructor:

struct foo_param
{
  template<typename T>
  foo_param(const T& t){data.reset(new foo_ostreamable_imp<T>(t));

  scoped_ptr<foo_ostreamable> data;

};

// foo_param can be written into ostream
ostream& operator<<(ostream& os,const foo_param& p)
{
 return p.data->output(os);

}

And finally, you define your classes:
class SuperClass
{
public:
        virtual void foo(const foo_param&) const = 0;

};

class SubClass: public SuperClass
{
public:
        virtual void foo(const foo_param& p) const { cout << p <<
endl;}

} ;

The compiler will automatically resolve with correct subtype:
SubClass s;
s.foo(1);
s.foo(0.1);
s.foo("bar");
...

If you want to keep/compare foo_param values, there is some management
to do such as deep copy and others to put it into canonical form. If a
type doesn't react as you want, you overload foo_param constructor.
</quote>
[snip]
I'm a bit confused (I struggle with abstract concepts). Why is your example
different from simply using polymorphism? Like this:

class Pet
{
public:
    virtual void Speak() = 0;

};

class Cat : public Pet
{
public:
    void Speak(){cout << "meow";}

};

class Dog : public Pet
{
public:
    void Speak(){cout << "woof";}

};

void DoSomething(const Pet& p)
{
    p.Speak();

}

Is it that in your example the contract for what a type is permitted to do
is specified outside its definition?

In your example, Cat and Dog have a common ancestor Pet. Which is not
always the case. In your original post, you would like to pass in a
virtual function types that are not related.

If you used simple polymorphism, you would have to explicitely
instanciate a wrapper for each type you want to support

Wrapper param1(1);
s.foo(param1);
Wrapper param2(0.1)
s.foo(param2);
Wrapper param3("bar")
s.foo(param3);

or you would have to restrict to const object

s.foo(1); // s.foo(Wrapper(1))
s.foo(0.1); // s.foo(Wrapper(0.1));
s.foo("bar"); // s.foo(Wrapper("bar"));

Depending on your design you may need one solution or the other.
 

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
474,432
Messages
2,571,682
Members
48,796
Latest member
Greg L.

Latest Threads

Top