Workaround for virtual function templates?

Joined
Nov 16, 2006
Messages
2
Reaction score
0
C++ does not allow virtual function templates. I am looking for a workaround.

The benefit of template arguments is they can be evaluated at compile time, which promises a great benefit in performance. In my code at home (that would be too big here), performance really matters!

I know a similar question has been posted before, but the answers were not really satisfactory. I wanted to give a simplified example, so it is more likely I get a useful advice!


My example:
A spaceship gets hit by a weapon. For this event, we need the spaceship and its type (both known only at run time), and the weapon type (known at compile time).

Code:
struct Spaceship {
    template<class Weapon> virtual void hit()=0;  // not allowed
};

struct XWing : Spaceship {
    template<class Weapon> void hit() {
        cout<<"\nX-Wing was hit by a "<<Weapon::toString();
    }
};

struct BWing : Spaceship{
    template<class Weapon> void hit() {
        cout<<"\nB-Wing was hit by a "<<Weapon::toString();
    }
}

//-----------------------------------------------------------------------

struct Missile {
    static char* toString() {
        return "missile";
    }
};

struct LaserGun {
    static char* toString() {
        return "laser gun";
    }
};

//-----------------------------------------------------------------------

int main()
{
    Spaceship* spaceship = new XWing();
    spaceship.hit<Missile>();
    char s;
    cin>>s;
    return 0;
}

For now I solved the problem like that.
Problem: code size = number of spaceships * number of weapons !!

Code:
struct Spaceship {
    virtual void hit_by_missile()=0;
    virtual void hit_by_laser()=0;
};

struct XWing : Spaceship {
    void hit_by_missile() {
        cout<<"\nX-Wing was hit by a missile";
    }
    void hit_by_laser() {
        cout<<"\nX-Wing was hit by a laser";
    }
};

struct BWing : Spaceship {
    void hit_by_missile() {
        cout<<"\nB-Wing was hit by a missile";
    }
    void hit_by_laser() {
        cout<<"\nB-Wing was hit by a laser";
    }
}

//-----------------------------------------------------------------------

int main()
{
    Spaceship* spaceship = new XWing();
    spaceship.hit_by_missile();
    char s;
    cin>>s;
    return 0;
}

Another workaround uses the classic OO mechanisms.
Problem: performance loss, because the weapon type is evaluated at run time.

Code:
struct Spaceship {
    template<class Weapon> virtual void hit()=0;
};

struct XWing : Spaceship {
    void hit(Weapon* weapon) {
        cout<<"\nX-Wing was hit by a "<<weapon->toString();
    }
};

struct BWing : Spaceship {
    void hit(Weapon* weapon) {
        cout<<"\nB-Wing was hit by a "<<weapon->toString();
    }
}

//-----------------------------------------------------------------------

struct Weapon {
    virtual char* toString()=0;
};

struct Missile : Weapon {
    char* toString() {
        return "missile";
    }
};

struct LaserGun : Weapon {
    char* toString() {
        return "laser gun";
    }
};

//-----------------------------------------------------------------------

int main()
{
    Spaceship* spaceship = new XWing();
    Weapon* weapon = new Missile();
    spaceship.hit(weapon);
    char s;
    cin>>s;
    return 0;
}
 
Last edited:
Joined
Nov 16, 2006
Messages
2
Reaction score
0
Found a Workaround !!

The following code looks like it solves the problem! Instead of a true template parameter, I use the argument type to give the methods a different signature.

I am not sure if this has the intended performance benefits. Will the argument "in hit(W* w)" generate overhead? The "(W*)0" can be evaluated at compile time, and the non-virtual functions can be inlined.. but will the compiler do that as I want?

And of course, it looks a bit weird with all the multi-inheritance. But that's the only way!

Code:
        Spaceship::AfraidOf<Missile>     Spaceship::AfraidOf<LaserGun>
                     |_________________________________|
                                      |
                               Spaceship::Ship
             _________________________|________________________
            |                |                |                |
  XWing::AfraidOf<Missile>   |     BWing::AfraidOf<Missile>    |
            |                |                |                |
            |    XWing::AfraidOf<LaserGun>    |   BWing::AfraidOf<LaserGun>
            |________________|                |________________|
                     |                                   |
                XWing::Ship                         BWing::Ship

Code:
struct Missile {
    static char* toString() {return "missile";}
};

struct LaserGun {
    static char* toString() {return "laser gun";}
};

//-----------------------------------------------------------------------

struct Spaceship {

    template<class W> struct AfraidOfWeapon {
        virtual void hit(W* w)=0;
    };
    
    struct Ship : AfraidOfWeapon<Missile>, AfraidOfWeapon<LaserGun> {
        template<class W> void hit() {
            W w;
            ((AfraidOfWeapon<W>*)this)->hit((W*)0);
        }
    };
};

//-----------------------------------------------------------------------

struct XWing {
    template<class W> struct AfraidOfWeapon : virtual Spaceship::Ship {
        void hit(W* w) {
            cout<<"\nX-Wing was hit by a "<<W::toString();
        }
    };
    struct Ship : AfraidOfWeapon<Missile>, AfraidOfWeapon<LaserGun> {};
};

//-----------------------------------------------------------------------

int main()
{
    Spaceship::Ship* spaceship = new XWing::Ship();
    spaceship->hit<Missile>();
    return 0;
}
 
Last edited:

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

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,905
Latest member
Kristy_Poole

Latest Threads

Top