Yola
Yola

Reputation: 19031

Deducing argument for a function that uses recurring template

i got the error from code below. What is wrong? Everything seems to be in place.

error C2784: 'void Menu::AddLeaf(Command,const int)' : could not deduce template argument for 'Command' from 'LauncherCommandChangeSimulation'

Command.h

template <class Receiver>
class Command
{
    virtual void Execute() = 0;
    ...
};

LauncherCommand.h

#include "Menu/Command.h"
#include "Internal/Launcher.h"
class LauncherCommand : public Command<Launcher>
{ ... };

class LauncherCommandChangeSimulation : public LauncherCommand
{ ... };

Menu.h

template <class T>
class Command;

class Menu
{
public:
    template <class T>
    void AddLeaf(Command<T> command, const int parentId);
};

Game.cpp

#include "Internal/Launcher.h"
#include "Menu/Menu.h"
#include "Menu/LauncherCommand.h"

LauncherCommandChangeSimulation command(...);

menu.AddLeaf(command, ...); // Error here

If i change call to AddLeaf on

menu.AddLeaf<Launcher>(command, simsNodeId);

then i get next error

error C2770: invalid explicit template argument(s) for 'void Menu::AddLeaf(Command,const int)'

Upvotes: 1

Views: 56

Answers (2)

Oktalist
Oktalist

Reputation: 14714

It works if the command parameter is taken by reference.

LIVE DEMO

This is because of §14.8.2.1(4):

In general, the deduction process attempts to find template argument values that will make the deduced A identical to A (after the type A is transformed as described above). However, there are three cases that allow a difference:

  • ...
  • ...
  • If P is a class and P has the form simple-template-id, then the transformed A can be a derived class of the deduced A. Likewise, if P is a pointer to a class of the form simple-template-id, the transformed A can be a pointer to a derived class pointed to by the deduced A.

But then you would need to deal with the object's lifetime management, so Mike is correct that you'll be wanting a smart pointer instead.

Upvotes: 2

Mike Seymour
Mike Seymour

Reputation: 254651

You're trying to pass a derived-class object to a function that takes the Command base class by value. That will try to slice the object, copying the base sub-object and discarding everything that makes it a LauncherCommand and a LauncherCommandChangeSimulation. Even if that worked, it would not be what you want; and in this case it won't work, since the base class is abstract and so can't be instantiated as a complete object.

You'll need some kind of indirection in order to store polymorphic objects in the menu. It looks like you'll need a further, non-template, base class, and AddLeaf will need to take and store a (preferably smart) pointer to that.

Upvotes: 3

Related Questions