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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions