Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple variadic templated delegate system

So, I've recently build a delegate system using c++11's variadic templates, and it works just as a charm.

However in the system I've built arguments to functions are given at creation-time (as I'd like), but now I'd also like to be able to pass some (variable) number of arguments at call-time. In order to achieve this, I went and redid my code, however is where I'm getting the issues;

error: parameter packs must be at the end of the parameter list
sorry, unimplemented: cannot expand ‘Arguments ...’ into a fixed-length argument list
error: type/value mismatch at argument 1 in template parameter list for ‘template<<declaration error>, class ... Params> class FunctionDelegate’

... and a lot more to come, so here's a snippet that spawned the issue;

template<typename... Params> 
class Runnable
{
    public:
        virtual void invoke(tuple<Params...> params) = 0;
        virtual ~Runnable() 
        {
        }
};

This is the parent class for my two delegates (FunctionDelegate and ObjectDelegate). This used to be an untemplated class (as invoke didn't take any arguments), however as I've a variadic template list to it, I had to modify my subclasses as well (obviously), and I've just added another variadic template to them;

template<typename... Arguments, typename... Params>
class FunctionDelegate : public Runnable<Params...>
{
    public:
        typedef void (*FunctionType)(Arguments..., Params...);

        FunctionDelegate(FunctionType function, tuple<Arguments...> args)
            : function(function), args(args)
        {
        }

        void invoke(tuple<Params...> params) 
        {
            callFunction(typename gens<sizeof...(Arguments)>::type(), params, typename gens<sizeof...(Params)>::type());
        }
    private:
        template<int... S, int... R>
        void callFunction(seq<S...>, tuple<Params...> params, seq<R...>)
        {
            function(get<S>(args)..., get<R>(params)...);
        }
    private:
        FunctionType function;
        tuple<Arguments...> args;
};

This however, does not seem to be allowed, atleast that's what I suspect, so;

  1. Is it allowed to have two variadic template lists?
  2. Is there some way, that I can hint the compiler, about which goes to which list? (namely the ones used in the constructor goes to Arguments, and the rest to Params).
  3. If there's simply no way to do this (using two variadic template lists), isn't it possible using one, Arguments and Parameters in the same variadic list, and then simply splitting that using the arguments to the constructor?
  4. Is there any other way to achieve what I'm trying? (except from using the plain old, non type-checked variadic parameter passing).

Any help or insight is welcome.

like image 280
Skeen Avatar asked Jun 22 '26 23:06

Skeen


2 Answers

No, you cannot use such code. You can use following for example

template<typename... Params>
class FunctionDelegate;

or

template<typename Arguments, typename Params>
class FunctionDelegate;

as Xeo suggests.

template<typename... Arguments, typename... Params>
class FunctionDelegate<tuple<Arguments...>, tuple<Params...>> : 
public Runnable<Params...> { // };
like image 160
ForEveR Avatar answered Jun 26 '26 01:06

ForEveR


Concerning your first two questions (the answers are "No" and "No"), paragraph 14.1/11 of the C++11 Standard specifies:

If a template-parameter of a class template or alias template has a default template-argument, each subsequent template-parameter shall either have a default template-argument supplied or be a template parameter pack. If a template-parameter of a primary class template or alias template is a template parameter pack, it shall be the last template-parameter. A template parameter pack of a function template shall not be followed by another template parameter unless that template parameter can be deduced or has a default argument (14.8.2). [ Example:

template<class T1 = int, class T2> class B; // error
// U cannot be deduced or specified
template<class... T, class... U> void f() { }
template<class... T, class U> void g() { }

—end example ]

Your example clearly violates the sentence in bold, which prohibits having more than one template argument pack on a (primary) class template.

like image 45
Andy Prowl Avatar answered Jun 26 '26 02:06

Andy Prowl



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!