What's the best way to have a variable number of template parameters?
Please consider this -probably poorly written- example :
class Command;
class Command : public boost::enable_shared_from_this<Command>
{
public :
void execute()
{
executeImpl();
// then do some stuff which is common to all commands ...
}
// Much more stuff ...
private:
virtual void executeImpl()=0;
// Much more stuff too ...
};
and :
class CmdAdd : public Command
{
public:
CmdAdd(int howMuchToAdd);
void executeImpl();
int _amountToAdd;
};
// implementation isn't really important here ....
With this, I can simply add a callback using this syntax :
boost::shared_ptr<Command> cmdAdd(CmdAdd(someValue));
cmdAdd->execute();
It works flawlessly. My "Command" class does much more things which are common to all commands, such as implementing undo, redo, progress report and so on, but I removed it from the code for the sake of readability.
Now my question is simple : is there a way to rewrite the command class, so that I can replace this call :
boost::shared_ptr<Command> cmdAdd(CmdAdd(someValue));
cmdAdd->execute();
by something like :
CmdAdd(someValue); // preferably
or CmdAdd->execute(someValue)
I've been thinking about that a lot but I have a conceptual problem : I wanted to template my Command class like
template <typename R,typename T1, typename T2, ..., typename Tn> class Command
{
R1 execute(T1 p1, ...,Tn pn)
{
return executeImpl(T1 p1, ...,Tn pn);
// then do some stuff which is common to all commands ...
}
}
but obviously, there's a problem here :
the syntax template <typename R,typename T1, typename T2, ..., typename Tn>
isn't legal C++ , AFAIK.
Do I have to write n versions of Command, like :
template <typename R> class Command
template <typename R,typename T1> class Command
template <typename R,typename T1, typename T2> class Command
...
and so on ? (not even sure this is gonna 开发者_C百科work indeed)
Or is there another, more elegant way to do this ? Is the syntax, mentioned here of any use there ? (function f;)
I've been looking at Loki's type lists and they seem to do the job. But I can't find anything that in Boost. I read on the web that boost::mpl is what one wants to use to implement typelists, but I'm a bit confused by MPL docs ?
Any insights on this ? Regads, D.
Interesting question :)
First of all, there is an issue you overlooked: you need a common base class for all Command
and this class cannot be templated if you are going to use a stack of them (for undo/redo).
Therefore you are stuck with:
class Command
{
public:
void execute();
private:
virtual void executeImpl() = 0;
};
I can understand your desire an execute function with parameters, but don't forget that anyway you would need to save those parameters for the undo/redo operation. It's just simpler to get them through the constructor.
However, you could still use a templated method to actually invoke a command:
template <class Command>
void execute() { Command cmd; cmd.execute(); }
template <class Command, class T0>
void execute(T0& arg0) { Command cmd(arg0); cmd.execute(); }
/// ...
int main(int argc, char* argv[])
{
execute<MyLittleCommand>("path", 3);
}
Which is close to the syntax you desired. Note that I have purposely forgotten about the stack here, in my mind you need to pass it to the execute
method for registration (once completed).
Not that I would also probably change the Command
design to get closer to a Strategy pattern:
struct CommandImpl
{
virtual ~CommandImpl();
virtual void executeImpl() = 0;
};
class Command
{
public:
template <class C>
static Command Make() { return Command(new C()); }
template <class C, class T0>
static Command Make(T0& arg0) { return Command(new C(arg0)); }
/// ....
void execute(CommandStack& stack)
{
mImpl->executeImpl();
stack.Push(*this);
}
private:
Command(CommandImpl* c): mImpl(c) {}
boost::shared_ptr<CommandImpl> mImpl;
};
It's the typical combination of Non Virtual Interface and Pointer to Implementation idioms.
AFAIK You can't really do this with the current standard of C++. Some boost code uses macros and other preprocessing to simulate variadic templates (I think boost::pool or boost::object_pool use something like that).
However, variadic templates are coming in the next standard C++0x and according to this page GCC already provide an implementation starting with v4.3 : http://gcc.gnu.org/projects/cxx0x.html
If you're using it, you can enable it by activating C++0x.
At first glance, variadic templates seem like the perfect solution. Unfortunately, they don't play well with virtual functions:
template <typename... Args>
void execute(Args&&... args)
{
executeImpl(std::forward<Args>(args)...);
}
This requires executeImpl
to be a virtual member function template, but there is no such thing in C++!
Variadic templates, as Klaim pointed out, are the ultimate solution to this problem. However, there is a way to allow a variable number of template arguments using type lists:
template <class H, class T>
struct typelist
{
typedef H head;
typedef T tail;
};
This allows you to write typelist<typelist<int, float>, double>
, for instance. It is a real pain in the neck to read and write, however, and is the main reason why boost::function uses the brute force approach (separate class for each number of template arguments): boost::function0, boost::function1, boost::function2, etc. for its backend implementation. It's just so much easier than traversing typelists recursively through template metaprogramming.
As for a general answer, I posted it in the other thread where you originally had this question along with another one.
精彩评论