Home > database >  Unable to deduce template arguments when using parameter pack in a member function argument
Unable to deduce template arguments when using parameter pack in a member function argument

Time:09-02

Why does compiler fail to deduce arguments types in this case ?

class MyArrayOfObjects{

    //assume this class contains a buffer of ObjectInArray

    template<typename ObjectType, typename ... ParamsT>
    inline void foreach(ObjectType* obj,void(ObjectType::* func)(ObjectInArray *, ParamsT&&... ), ParamsT&&... params) const {
        for (unsigned int i = 0; i < this->internalSize; i  ) {
            (obj->*func)(this->buffer[i], params...);
        }
    }
}   

Whereas it succeed to deduce them in the error message :

void MyArrayOfObjects::foreach(ObjectType *,void (__cdecl ObjectType::* )(ObjectInArray *,ParamsT &&...),ParamsT &&...) const': could not deduce template argument for 'void (__cdecl ObjectType::* )(ObjectInArray *,ParamsT &&...)' from 'void (__cdecl MyOtherObjectType::* )(ObjectInArray *,int,const char *)

I try to use it this way :

/*
myArray is a MyArrayOfObjects
myOtherObject is a MyOtherObjectType that contains a public function : 
void MyOtherObjectType::callThatInLoop(ObjectInArray*,int,const char *)
*/

myArray.foreach(myOtherObject, &MyOtherObjectType::callThatInLoop, 10, "hello world"); 

Why can't it understand that ParamsT should simply be "int,const char *" ?

CodePudding user response:

The parameter is:

void(ObjectType::* func)(ObjectInArray *, ParamsT&&... )

That accepts a member function pointer which takes one pointer argument followed by arbitrary rvalue reference arguments.

The call is:

myArray.foreach(myOtherObject, &MyOtherObjectType::callThatInLoop, 10, "hello world"); 

That is trying to pass a member function pointer with one pointer argument and a couple arguments passed by value.

Because these are incompatible, deduction fails. A simpler example:

void test(int, const char*);

template <typename... Params>
void foreach1(void (*func)(Params&&...));

void call_foreach1() {
  // foreach1(test); // error: deduction fails
}

template <typename... Params>
void foreach2(void (*func)(Params...));

void call_foreach2() {
  foreach2(test); // Params deduced as int, const char*
}

See https://godbolt.org/z/qK9rqnPKc

In the example, the focus on the exact form of member function pointer seems misplaced. What matters is that you can call it with the correct parameters, is it not? That's easier to express:

template <typename Object, typename Callable, typename ... Params>
  requires std::invocable<Callable, Object*, ObjectInArray*, const Params&...>
void foreach(Object* object, Callable&& callable, const Params&... params) const {
    for (std::size_t i = 0; i < internalSize; i  ) {
        std::invoke(callable, object, buffer[i], params...);
    }
}

CodePudding user response:

The accepted answer worked, but I was too limitated with strict parameters types in several cases, ie : "const char[12]" that is not "const char*" as @paolo said, or when using this with function that takes references for some parameters

Final solution is to use 2 parameters packs, this is a little bit more permissive when typing code and especially it deals with parameters conversion if possible, but you are still warned at compile time if the called function can't be called after automatic cast of parameters, so no worries about a hidden runtime crash.

class ObjectInArray{ };

class MyOtherObjectType{
    public:
        void test1(ObjectInArray*,int, const char*);
        void test2(ObjectInArray*,int, float&);
};

template<typename ObjectType, typename ... FuncParamsT, typename ... ParamsT>
void foreach(ObjectType* obj,void(ObjectType::* func)(ObjectInArray *, FuncParamsT... ), ParamsT&&... params) {
    for (unsigned int i = 0; i < 100; i  ) {
        ObjectInArray tmp;
        (obj->*func)(&tmp, params...);
    }
}

//testing the thing
void call_foreach() {
    MyOtherObjectType obj;
    foreach(&obj,&MyOtherObjectType::test1,10,"hello");
    foreach(&obj,&MyOtherObjectType::test2,10,12.5);
}
  • Related