0

Sorry if this question doesn't make any sense.I don't have much experience with templates. I want to make a generic function which can store a list of static function inside a class and later execute them all.I also need to pass the the reference of objects to each of this function for their execution.I achieved this without using templates

#ifndef _handle_connection
#define _handle_connection

#include <string>
#include <utility>
#include <vector>
#include <errno.h>
#include <iostream>

namespace handle_connection
{
    class handleconnection
    {
        std::vector<std::pair<void *, int (*)(void *, std::string, int)>> funclist;

    public:
        //adds function to the list of function to excecute
        //@param reference of the object
        //@param : int (*func)(void* ,std::string,int) function
        void use(void *object, int (*func)(void *context, std::string response, int new_socket))
        {
            funclist.push_back(std::make_pair(object, func));
            
        }

        //call
        //@param : string response
        //@param : int socket
        int call(std::string response, int new_socket)
        {
            for (auto c : funclist)
            {
                //need to extract the type of the reference object T
                if (c.second(c.first, response, new_socket) == 0) //code is incomplete
                    return 0;
            }
            return -1;
        }
    };
} // namespace handle_connection

#endif

class foo
{
    std::string path = "it worked for foo";

public:
    static int func(void *object, std::string text, int socket);
};

class bar
{
    int num = 10;
    std::string path = "it worked for bar";

public:
    static int func(void *object, std::string text, int socket);
};

int foo::func(void *object, std::string text, int socket)
{
    std::cout << static_cast<foo *>(object)->path;
    return -1;
}

int bar::func(void *object, std::string text, int socket)
{
    std::cout << static_cast<bar *>(object)->path;
    return 0;
}

int main()
{
    foo obj1;
    bar obj2;

    handle_connection::handleconnection connections;
    connections.use(&obj1, foo::func);
    connections.use(&obj2, bar::func);
    connections.call("hello", 1);
}

but for this i have to pass void pointer of objects to my function and cast it inside the definition but i dont want to do that.

//not void pointer
template<class T>
void use(void *object, int (*func)(T *context, std::string response, int new_socket))
        {
            funclist.push_back(std::make_pair(object, func));
            //need to store the type information of reference object( T)
            //code is incomplete
            // i need to store the variable T as well somehow
        }

if my understanding of template is not correct can someone tell me what am i thinking wrong.

Arjun U S
  • 199
  • 10
  • 1
    The problem in that `T` isn't a variable, it's a *type*, and you can't store types. But there's really nothing wrong with `void*`, any kind of pointer can be implicitly converted to `void*`, but you need a `reinterpret_cast` to cast it back. However the function being called should know that the type of `context` really is and should be able to easily cast it. Using `void*` is also very common when it's not really possible to know the type, which is the case here. – Some programmer dude Jun 26 '20 at 11:53
  • 1
    On another note I suggest you use [`std::function`](https://en.cppreference.com/w/cpp/utility/functional/function) for the `func` argument. By doing that you could pass any kind of callable object (like [lambdas](https://en.cppreference.com/w/cpp/language/lambda) or functor objects). – Some programmer dude Jun 26 '20 at 11:54
  • @Someprogrammerdude What exactly is T here , when the function is initiated with T can't we some how store this information? – Arjun U S Jun 26 '20 at 11:58
  • `T` is a *type* (as I already mentioned), like `int` or `float` or `std::string`. There's no way to store the type `int` (for example). – Some programmer dude Jun 26 '20 at 11:59
  • [here](https://stackoverflow.com/questions/2562176/storing-a-type-in-c) thank you sir i though of T as variable now i am somewhat clear – Arjun U S Jun 26 '20 at 12:02
  • I think it would be better to store binded function, i.e. first `std::bind` object to function, then store resulting function in list. That way you don't need to save object separately and all function signatures should be same. – sklott Jun 26 '20 at 12:10

1 Answers1

1

To simplify things, you can just use std::function and wrap callbacks as lambda's:

class handleconnection
{
    std::vector<std::function<int(std::string const&, int)>> funclist;

public:
    void use(std::function<int(std::string const&, int)> const& func) {
        funclist.push_back(func);
    }

    int call(std::string const& response, int new_socket) {
        for (auto& func : funclist) {
            if (func(response, new_socket) == 0) {
                return 0;
            }
        }
        return -1;
    }
};

int main() {
    handleconnection c;
    c.use([](std::string const& msg, int sock) {
        std::cout << "Func 1: " << msg << ", " << sock << "\n";
        return 1;
    });
    std::string some_object = "Some Object";
    c.use([&some_object](std::string const& msg, int sock) {
        std::cout << "Func 2: " << msg << ", " << sock << ", " << some_object << "\n";
        return 1;
    });
    c.call("test", 123);
}

You can capture any object in the lambda's [] clause and use it inside... no need to pass T, void* or alike.

rustyx
  • 80,671
  • 25
  • 200
  • 267
  • connections.use([&obj1](std::string resp, int socket) { return foo::func(&obj1, resp, socket); }); when capture objects by reference i am getting an error "no suitable conversion function from "lambda []int (std::__cxx11::string resp, int socket)->int" to "int (*)(std::__cxx11::string response, int new_socket)" exists" – Arjun U S Jun 26 '20 at 12:32
  • Again you're overcomplicating. Just do `connections.use([&obj1](std::string resp, int socket) { return obj1.func(resp, socket); });`. `foo:func` can be made a non-static member function, and so already receive the implicit `this` pointer. (note: consider passing std::string by a const-reference, is much faster) – rustyx Jun 26 '20 at 12:46