Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

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

0 views
Skip to first unread message

ted orange

unread,
Dec 23, 2009, 3:54:28 AM12/23/09
to
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.

Michael Doubez

unread,
Dec 23, 2009, 4:13:07 AM12/23/09
to

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

ted orange

unread,
Dec 23, 2009, 5:04:32 AM12/23/09
to

"Michael Doubez" <michael...@free.fr> wrote in message
news:7383d7f5-bc8f-446a...@r5g2000yqb.googlegroups.com...

--
Michael

Hi Michael,

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


Michael Doubez

unread,
Dec 23, 2009, 6:32:17 AM12/23/09
to
On 23 déc, 11:04, "ted orange" <nos...@please.com> wrote:
>> "Michael Doubez" <michael.dou...@free.fr> wrote in message
>> news:7383d7f5-bc8f-446a...@r5g2000yqb.googlegroups.com...

>> On 23 déc, 09:54, "ted orange" <nos...@please.com> wrote:
>> > 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

ted orange

unread,
Dec 23, 2009, 7:43:48 AM12/23/09
to

"Michael Doubez" <michael...@free.fr> wrote in message
news:7d56071c-3291-499d...@a21g2000yqc.googlegroups.com...

On 23 d�c, 11:04, "ted orange" <nos...@please.com> wrote:
>> "Michael Doubez" <michael.dou...@free.fr> wrote in message
>> news:7383d7f5-bc8f-446a...@r5g2000yqb.googlegroups.com...

};

};

scoped_ptr<foo_ostreamable> data;

};

}

};

} ;

--
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?

Michael Doubez

unread,
Dec 23, 2009, 10:31:44 AM12/23/09
to
On 23 déc, 13:43, "ted orange" <nos...@please.com> wrote:
> "Michael Doubez" <michael.dou...@free.fr> wrote in message
>
> news:7d56071c-3291-499d...@a21g2000yqc.googlegroups.com...

> On 23 déc, 11:04, "ted orange" <nos...@please.com> wrote:
>
>
>
> >> "Michael Doubez" <michael.dou...@free.fr> wrote in message
> >>news:7383d7f5-bc8f-446a...@r5g2000yqb.googlegroups.com...
> I have posted an example not so long ago:http://groups.google.fr/group/comp.lang.c++/browse_frm/thread/724c2ca...
[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.

--
Michael

0 new messages