Search code examples
c++c++11variadic-templates

Conflicting types for variadic parameter


I am trying to write a general invocation function.

It has the following syntax:

template<int Index, typename ReturnType, typename... Parameter>
ReturnType invokeGlobalFunction(Parameter... parameters)
{
    return invocator->invoke<ReturnType>(Index, parameters...);
}

Next, I try to derive two different function points from it, like this:

registerFunction(::someGlobalFunction, &invokeGlobalFunction<0, void>);
registerFunction(::someOtherFunction, &invokeGlobalFunction<1, int>);

Where someGlobalFunction has the prototype void someGlobalFunction() and someOtherFunction has the prototype int someOtherFunction(int, const char *).

On the first call, it works like a charm, however the second call throws the error: candidate template ignored: deduced conflicting types for parameter 'Parameter' (<int, const char *> vs. <>).

This implies, that the compiler (g++ 7.4.0 on an Ubuntu system btw.) does not overload the invokeGlobalFunction with the different parameter sets like I expected him to.

A note: When I explicitly set the parameter types on the call

registerFunction(::someOtherFunction, &invokeGlobalFunction<1, int, int, const char *>);

the compiler happily takes it, but I'd like to avoid that, if possible.

As a bonus, it would be great, if I could somehow create a unique function each time the index changes, because that would allow me to have functions with identical parameters but differing return types (which is illegal as far as I know).

Thank you.


Solution

  • but I'd like to avoid that, if possible.

    Not with template functions, as far I know.

    The problem is that a template parameter isn't a single object but a set of object where a function can accept only an object from the set.

    When you write

    &invokeGlobalFunction<1, int>
    

    you choose a precise function with Index = 1, ReturnType = int and (this is the point) an empty Parameter... list.

    Suggestion: if you can, transform invokeGlobalFunction() in a template struct with a template method.

    Something as

    template <int Index, typename ReturnType>
    struct invokeStruct
     {
       template <typename ... Parameters>
       ReturnType operator() (Parameters ... parameters)
        {
          // ... 
        }
      };
    

    This way you have a set of struct with, in every struct, a set of operator() in it; passing a invokeStruct<1, int>{} as argument, you pass a single object but, inside it, you have available a set of method.