Skip to main content
GameDev.net gamedev.net
🔒 Locked

Polymorphism and templates

Started by terry_burns85 Mar 4, 2009 at 10:02 AM 11 replies 3.1k views
Original Post
terry_burns85
terry_burns85
Hi guys, I was wondering if someone could shed some light on a problem im having. The problem is that i am looking to create an abstract class, but am having some trouble in allowing it to have templates included on its methods.

class MyAbstractClass
{
public:
    template <typename T>
    virtual void MyMethod( T value ) = 0;
};

can anyone hint at a solution to using this? sidenotes: The error is - error C2898: member function templates cannot be virtual IDE - Visual Studio 2008
---Terence Burns---
Nanoha
Nanoha
might have to make the whole thing a template class


template
class MyAbstractClass
{
public:
virtual void MyMethod( T value ) = 0;
};
Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.
Guthur
Guthur
I think the error message says it all really :) Didn't know they couldn't be virtual actually, it kind of makes sense though because virtuals are resolved at runtime whereas templates need to be resolved at Compile time.

Are you from Belfast Norn Iron :p
Innovation not reiterationIf at any point I look as if I know what I'm doing don't worry it was probably an accident.
GenuineXP
GenuineXP
The error message is spot on. You simply cannot create virtual member function templates in C++.

One way to get around this (sometimes) is often called a concept, where you supply a class as a template parameter that should provide some interface and implements said concept.

template<typename T>class foo {public:    void bar() {        T::baz();    }};

I'm not sure what you're going for, but maybe that can be helpful.

EDIT: Ah yes, as Nanoha said, creating a class template rather than a template member function may also get around the problem and would probably be cleaner than using the technique I described.
terry_burns85
terry_burns85
Hi fellas,

cheers for the input, i know that the error message for once is pretty self explanatory,
I am aware of overloading the method, however, that would mean including a substantial amount of code to being duplicated, and thats not really an option for now.
---Terence Burns---
Codarki
Codarki
What are the types of T? Can it be abstract interface?

Its not yet clear what your problem is, on higher level. What do you want to do?
dascandy
dascandy
You can't make a virtual template function because the compiler has to decide at compile time:

- What functions to put into the virtual function table (IE, all overloads etc).
- What templates to instantiate and with what parameters.

A virtual template function would have between 0 and infinite actual instantiations (think an int template that would already allow 4.3 billion - close enough to infinity). You can't reserve enough space for that in a virtual function table. Even if you could, you wouldn't be able to fill it with the appropriate functions - as they need to be generated and filled in at compile time - where you tell it that they will be decided upon at runtime (because of the virtual).

To repeat the one right above me, what are you trying to accomplish that makes you run into this problem?
NotAYakk
NotAYakk
class MyAbstractClass{protected:    virtual void MyVMethod(int value) = 0;    virtual void MyVMethod(double value) = 0;    virtual void MyVMethod(char* value) = 0;public:    template <typename T>    void MyMethod( T value ) { MyVMethod( value ); }};template<typename C>class MyTemplateClassImpl: public MyAbstractClass{  // technically we don't need this -- we could  // just do the same in each virtual method.  // But, I find this to be cleaner.  template<typename T>  void MyMethodTemplateHelper( T value ) {    C* self = static_cast<C*>(this);    self->MyMethodImpl( value );  }public:  virtual void MyVMethod(int value) { this->MyMethodTemplateHelper(value); }  virtual void MyVMethod(double value) { this->MyMethodTemplateHelper(value); }  virtual void MyVMethod(char* value) { this->MyMethodTemplateHelper(value); }};class MyClassImpl: public MyTemplateClassImpl<MyClassImpl>{public:  // this must either be public,  // or we have to befriend MyTemplateClassImpl<MyClassImpl>  template<typename T>  void MyMethodImpl(T value) {    std::cout << "My value is [" << value << "]!\n";  }};


Here I move the runtime polymorphism of MyAbstractClass into compile time polymorphism via the CRTP (google it) of MyTemplateClassImpl.

Each implementation class need only implement the MyMethodImpl(), and MyTemplateClassImpl does the dispatch for you.

Each type you support needs to be added once to MyAbstractClass (as that defines the binary runtime interface of the abstract class, and thus must be fully described _within_ MyAbstractClass), and once to MyTemplateClassImpl (as that redirects the binary virtual runtime dispatch decisions to template based compiletime dispatch).

Welcome to the rabbit hole.
loufoque
loufoque
Unlike what is usually claimed, template virtual functions wouldn't be especially hard to do. It would just require generating the vtables at link-time.

This would be an awesome feature, also. Full dynamic typing, such as duck typing, becomes possible.
Zahlman
Zahlman
Quote:
Original post by loufoque
Unlike what is usually claimed, template virtual functions wouldn't be especially hard to do. It would just require generating the vtables at link-time.


So the object file would contain some kind of stub saying "instantiate this template for each actually-used template type in the vtable here", and then all those instantiations would be looked up by the linker (sounds time-consuming). I'm guessing that linkers are (or at least were originally) designed to expect resolved symbols to "fit" in the space allocated by their placeholders (so that the files could be loaded into memory, modified in place and concatenated together into the final result, without needing to move chunks around to make more room), so this would remove that potential optimization in the linker. But yes, it doesn't sound hard. Just like more work than anyone wants (wanted) to do.

And thanks BTW; I hadn't previously considered this in detail. :)

Quote:
This would be an awesome feature, also. Full dynamic typing, such as duck typing, becomes possible.


I'm somehow not envisioning just what you have in mind here :s
loufoque
loufoque
Quote:
So the object file would contain some kind of stub saying "instantiate this template for each actually-used template type in the vtable here", and then all those instantiations would be looked up by the linker (sounds time-consuming). I'm guessing that linkers are (or at least were originally) designed to expect resolved symbols to "fit" in the space allocated by their placeholders (so that the files could be loaded into memory, modified in place and concatenated together into the final result, without needing to move chunks around to make more room), so this would remove that potential optimization in the linker. But yes, it doesn't sound hard. Just like more work than anyone wants (wanted) to do.

For every instantiation of a template virtual function of a class, you need to instantiate the template virtual function of all derived classes. Then you can create the virtual function tables accordingly.
The ability to instantiate templates at link-time, is actually required by a standard feature that basically no compiler supports: export template.
This does require encoding the definition of the template files in the object files.

Several compilers also optimize code at link-time (it is a very good idea to do so since needed for inlining and const propagation against translation units), and already embed in objects files an intermediate representation of the code. Which however doesn't really care about templates, typically.

Quote:
I'm somehow not envisioning just what you have in mind here :s

You could do something like a boost::variant where the set of possible types that can be held is not predefined at compile-time.
So now you can do a generic visitor over a non-finite set of types. Duck typing is just that, except you need to check whether the type supports the operation. If it does, do it, otherwise throw an error.
This is fairly easy to detect with SFINAE for expressions.

So assuming you have operator. overloading implemented in terms of polymorphic lambdas (which is not planned in C++ at the moment, but it's just for syntactic sugar purposes), you can write:

duck foo = 42;foo.push_back(1.0f); // throws, foo is an int and doesn't have a matching member functionfoo = std::vector<float>();foo.push_back(1.0f); // doesn't throw, foo now a vector of floats with one element, 1.0f


That's just like in Python or other languages, except it's much more efficient and it integrates perfectly with any C++ type.

Note that with current C++, you can do the same except you'll have to limit duck to a set of possibilities.
That set a possibilities may allow anything Python does, but won't integrate with any C++ type.
phresnel
phresnel
Quote:
Original post by terry_burns85
Hi guys,

I was wondering if someone could shed some light on a problem im having.
The problem is that i am looking to create an abstract class, but am having some trouble in allowing it to have templates included on its methods.

*** Source Snippet Removed ***

can anyone hint at a solution to using this?

sidenotes:
The error is - error C2898: member function templates cannot be virtual
IDE - Visual Studio 2008



This should give a pretty satisfying explanation.
NotAYakk
NotAYakk
typedef function< duck( array< duck >& ) > duck_method;struct duckImpl;struct duck {  shared_ptr<duckImpl> pImpl;  // to call a method of a duck, call Call with the name  // of the method, and the arguments to the method  // It is then dispatched through getMethod of the pImpl,  // which can make arbitrary choices based on the name  // of the method and the implementation of pImpl:  template<typename Args...>  duck Call( string name, Args... args ) {    if (!pImpl) throw null_duck();    return pImpl->getMethod( name )( array<duck>(args) );  }  duck();   // all operators redirected to call the appropriate getMethod in pImpl.};struct duckImpl {  virtual duck_method getMethod( string name ) = 0;  virtual duck hasMethod( string name ) = 0;  virtual duck begin() = 0;  virtual duck end() = 0;  virtual goose metadata() = 0;};

Viola, python in C++. ;)

You need primitives (like IO and addition etc) implemented magically via a framework. In actuality, the duckImpl wouldn't be nearly that opaque, so you can do really funkey stuff (like printing out values!) and changing the properties and methods of your duck at "run time".

You'd probably want to implement a class/instance pattern (where your instance ducks know their class duck, and if they don't find a method in their instance duck-map, they go ask their class duck for the method, who looks at it's parent class if it cannot find it, etc).

You'd need a way to register a method with a duck and the like. And maybe a non-property based duck member variable option for efficiency.

Each duckImpl then becomes:
Access to it's parent instance duck via GetParent().
Access to it's class's duck via GetClass().
A collection of duck_methods. GetFunction return the duck_method, while GetMethod gets the duck_method, binds the first parameter to a duck pointing at the duckImpl, and then returns that function.
A collection of duck member variables.
GetMember does a member lookup in itself, then in it's parent instance.

classes are simply ducks that happen to be of the class duckclass.

duckclass is a duck class that is of the class duck class. It notices this, and refuses to recurse forever looking for methods etc.

But really, just use python.


[Edited by - NotAYakk on March 5, 2009 5:19:47 PM]

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.