0

I know the title may be confusing. I created an "Array" data structure class which has a function called "Iterate". It accepts a function pointer (lambda) and iterates all the nodes with that function. Code:

    void Iterate(void(*function)(T* value))
    {
        if (Empty()) return;
        for (Node* iter = start; iter != nullptr; iter = iter->post)
            function(iter->value);
    }
// Function Call

DataStructure<int> test;
test.Iterate([](int i){ i = 0; });

This function works fine, but sometimes I need some arguments from outside to pass in. It can be done like this:

    template<class U>
    void Iterate(void(*function)(T* value, U a), U u)
    {
        if (Empty()) return;
        for (Node* iter = start; iter != nullptr; iter = iter->post)
            function(iter->value, u);
    }

// Function call
DataStructure<int> test;
test.Iterate<float>([](int i, float e){ i = e; }, 10.f);

And it works fine too, but I did not figure out how to do it with "...T". So the function can accept several arguments without having to overload the same function with x templates.

What I tried it:

    template<class ...U>
    void Iterate(void(*function)(T*, U...), U... u)
    {
        if (Empty()) return;

        for (Node* iter = start; iter != nullptr; iter = iter->post)
            function(iter->value, u);
    }

But it simply not works. It returns an error:

C++ no instance of overloaded function matches the argument list argument types are: (lambda []void (DataStructureType* data, Arg1 audio, Arg2 dt)->void, Arg1, Arg2)object type is: DataStructure<DataStructureType *>

cigien
  • 57,834
  • 11
  • 73
  • 112
ArEss
  • 31
  • 4
  • 1
    "a function pointer (lambda)" only non capturing lambdas can be converted to a function pointer. if you want a lambda as parameter you should not require a conversion. – 463035818_is_not_an_ai Feb 15 '23 at 12:21
  • On a different note, I recommend you use templates for the callable object as well, as then you can use *any* callable object, not only those that can be converted to pointers to non-member functions. For example, your code can't currently handle a lambda with captures- – Some programmer dude Feb 15 '23 at 12:24
  • As for your problem, since `u` is a parameter pack you need `...` in there somewhere as well. *And* I also recommend you do some research about *perfect forwarding* and [`std::forward`](https://en.cppreference.com/w/cpp/utility/forward). – Some programmer dude Feb 15 '23 at 12:25
  • You probably don't need this at all. Instead of passing `U...` to `Iterate`, capture everything in the lambda. Of course you will need to modify `Iterate` to accept capturing lambdas. – n. m. could be an AI Feb 15 '23 at 12:40

1 Answers1

2

Better not require a conversion to function pointer when not necessary. Only non capturing lambdas can convert to a function pointer. Once you fix that you can use a lambda expression that captures the additional parameter:

template <typename F>
void call_it(F f) {
     for (int i=0;i<100;++i) f(i);
}

int main() {
    auto f1 = [](int i,float x) {return i*x; };
    float z = 0.2f;
    call_it( [&](int i) { return f1(i,z); });
}

The problem with our approach is that you cannot have implicit conversions and template argument deduction at the same time. If you use an explicit cast it works:

template<class T,class ...U>
void iterate(void(*function)(T, U...), U... u) {
            function(42, u...);
}

void foo(int,float) {}

int main() {
    auto f1 = [](int i,float x) {};    
    iterate(static_cast<void(*)(int,float)>(f1),42.f);
}
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • A simpler way to convert a non-capturing lambda to a function pointer is to use the `+` unary operator, then the `static_cast` is not needed, eg: `iterate(+f1, 42.f);` See https://stackoverflow.com/questions/18889028/ – Remy Lebeau Feb 15 '23 at 20:58