Skip to content

A better delegate type definition? #27

@konard

Description

@konard
#include <iostream>
#include <memory>
#include <concepts>
#include <functional>

struct Object
{
    void Method(const char *str) 
    {
        std::cout << "Object::Method(" << str << ")" << std::endl;
    }
};

// For diagnostics
template <typename M>
struct PointerType {
    // template <typename C, typename T>
    // static T get_member_type(T C::*v);

    template <typename TClass, typename TReturn, typename TArg>
    static TClass get_class_type(TReturn (TClass::*func)(TArg));

    template <typename TClass, typename TReturn, typename TArg>
    static TReturn get_return_type(TReturn (TClass::*func)(TArg));

    template <typename TClass, typename TReturn, typename...TArg>
    static std::tuple<TArg...> get_argument_types(TReturn (TClass::*func)(TArg...));

    typedef decltype(get_class_type(static_cast<M>(nullptr))) class_type;
    typedef decltype(get_return_type(static_cast<M>(nullptr))) return_type;
    typedef decltype(get_argument_types(static_cast<M>(nullptr))) argument_types;
};

template <auto method>
class Delegate
{
    using TClass = typename PointerType<decltype(method)>::class_type;
    using TReturnType = typename PointerType<decltype(method)>::return_type;
    using TArgsTuple = typename PointerType<decltype(method)>::argument_types;

    std::shared_ptr<TClass> object;

public:
    Delegate(std::shared_ptr<TClass> object) : object(std::move(object)) { }

    template<typename ...TArgs>
    requires std::same_as<TArgsTuple, std::tuple<TArgs...>>
    TReturnType operator()(TArgs... args)
    {
        return (*object.*method)(std::forward<decltype(args)>(args)...);
    }
};

auto x = [](const char *str)
{
    std::cout << "Setter::Set(" << str << ")" << std::endl;
};

struct Setter : std::enable_shared_from_this<Setter>
{
    void Set(const char *str)
    {
        std::cout << "Setter::Set(" << str << ")" << std::endl;
    }
};

struct SetterExtender
{
    std::shared_ptr<Setter> setter = std::make_shared<Setter>();

    Delegate<&Setter::Set> Set = setter;
};

// template<typename T>
void call(auto&& delegate)
{
    delegate("calling delegate passed to funciton");
}

int main()
{
    Delegate<&Object::Method> x(std::make_shared<Object>());

    x("call from main");

    SetterExtender se1;

    se1.Set("call from main 1");

    call(se1.Set);

    call([&](const char *str){ se1.Set(str); });

    std::cout << typeid(PointerType<decltype(&Object::Method)>::class_type).name() << std::endl;
    std::cout << typeid(PointerType<decltype(&Object::Method)>::return_type).name() << std::endl;
    std::cout << typeid(PointerType<decltype(&Object::Method)>::argument_types).name() << std::endl;
}

https://godbolt.org/z/a4v1n6GK8

It is possible to pass a pointer to the function into the template.

Maybe we can make it useful somehow?

What if instead of

Delegate<void(const char *)> memberMethod(std::make_shared<Object>(), &Object::Method);

We could write something like this:

Delegate<&Object::Method> memberMethod(std::make_shared<Object>());

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions