有什么方法可以改进这个Delegate<void(int&)>::Bind<TestStruct&,&TestStruct::SomeFunction>(estStruct,Value)语法吗? [英] Is there a way to improve this Delegate<void(int&)>::Bind<TestStruct&, &TestStruct::somefunction>(testStruct, value) syntax?

查看:60
本文介绍了有什么方法可以改进这个Delegate<void(int&)>::Bind<TestStruct&,&TestStruct::SomeFunction>(estStruct,Value)语法吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现一个委托类型,该类型将与泛型回调一起使用,并在存在重载集的情况下工作。

为简化起见,此处摘录了类,并将绑定方法实现为静态函数以简化问题。

template <typename Signature>
class Delegate;

template <typename Ret, typename... Args>
struct Delegate<Ret(Args...)> {
    using Trampoline_T = Ret (*)(void*, Args&&...);
    using TrampolineConst_T = Ret (*)(const void*, Args&&...);

    using Function_Sig = Ret(Args...);
    using Function_Ptr = std::add_pointer_t<Function_Sig>;

    template <typename Instance_T>
    using MemberFunction_Sig = Ret(std::remove_reference_t<Instance_T>&,
                                   Args...);
    template <typename Instance_T>
    using MemberFunction_Ptr =
        Ret (std::remove_reference_t<Instance_T>::*)(Args...);
    template <typename Instance_T>
    using MemberFunctionConst_Ptr =
        Ret (std::remove_reference_t<Instance_T>::*)(Args...) const;
    template <typename Instance_T>
    using MemberFunctionConstOrNot_Ptr =
        std::conditional_t<std::is_const_v<std::remove_reference_t<Instance_T>>,
                           MemberFunctionConst_Ptr<Instance_T>,
                           MemberFunction_Ptr<Instance_T>>;

    template <typename Instance_T, MemberFunctionConstOrNot_Ptr<Instance_T> fct, typename T>
    static void Bind(T&& instance, auto&& value) {

        if constexpr (!std::is_const_v<std::remove_reference_t<Instance_T>>) {
            Trampoline_T trampoline = [](void* storage, Args&&... args) -> Ret {
                std::invoke(
                    fct,
                    *reinterpret_cast<std::remove_reference_t<Instance_T>*>(
                        storage),
                    std::forward<decltype(args)>(args)...);
            };
            trampoline(&instance, value);
        } else {
            TrampolineConst_T trampoline = [](const void* storage,
                                              Args&&... args) -> Ret {
                std::invoke(
                    fct,
                    *reinterpret_cast<std::remove_reference_t<Instance_T>*>(
                        storage),
                    std::forward<decltype(args)>(args)...);
            };
            trampoline(&instance, value);
        }
    }

    template <typename Instance_T>
    static void Bind(Instance_T&& instance, auto&& value) {
        if constexpr (!std::is_const_v<std::remove_reference_t<Instance_T>>) {
            Trampoline_T trampoline = [](void* storage, Args&&... args) -> Ret {
                std::invoke(
                    *reinterpret_cast<std::remove_reference_t<Instance_T>*>(
                        storage),
                    std::forward<decltype(args)>(args)...);
            };
            trampoline(&instance, value);
        } else {
            TrampolineConst_T trampoline = [](const void* storage,
                                              Args&&... args) -> Ret {
                std::invoke(
                    *reinterpret_cast<std::remove_reference_t<Instance_T>*>(
                        storage),
                    std::forward<decltype(args)>(args)...);
            };
            trampoline(&instance, value);
        }
    }
};

现在将此类类型与对象测试一起使用

class TestStruct {
   public:
    constexpr static int m_staticValue = 42;
    uint8_t m_value = m_staticValue;

    void somefunctionGeneric(auto& value) {
        std::cout << "somefunctionGeneric " << value << "
";
    }
    void somefunctionGeneric(auto& value) const {
        std::cout << "somefunctionGeneric const " << value + 1 << "
";
    }
    void somefunction(int& value) {
        std::cout << "somefunction " << value << "
";
    }
    void somefunction(int& value) const {
        std::cout << "somefunction const " << value + 1 << "
";
    }

    void operator()(auto& value) {
        std::cout << "operator()(auto&) " << value << "
";
    }
    void operator()(auto& value) const {
        std::cout << "operator()(auto&) const " << value + 1 << "
";
    }
    void operator()(int& value) {
        std::cout << "operator()(int&) " << value << "
";
    }
    void operator()(int& value) const {
        std::cout << "operator()(int&) const " << value + 1 << "
";
    }
};

您应该这样使用它:

int value = 42;
double valueDouble = 42;
TestStruct testStruct;
Delegate<void(int&)>::Bind<TestStruct&, &TestStruct::somefunction>(testStruct, value);
Delegate<void(double&)>::Bind<TestStruct&,&TestStruct::somefunctionGeneric<double>>(testStruct, valueDouble);

Delegate<void(int&)>::Bind(testStruct, value);
Delegate<void(double&)>::Bind(testStruct, valueDouble);

const TestStruct testStructConst;
Delegate<void(int&)>::Bind<const TestStruct&, &TestStruct::somefunction>(testStructConst, value);
Delegate<void(double&)>::Bind<const TestStruct&, &TestStruct::somefunctionGeneric<double>>(testStructConst, valueDouble);

Delegate<void(int&)>::Bind(testStructConst, value);
Delegate<void(double&)>::Bind(testStructConst, valueDouble);

Compiler explorer code

我希望改进绑定调用语法。我必须将类和函数作为模板传递。我觉得有一些技巧可以改善这一点。类似于使用类模板来推断类型。这可能是不可能的,如果知道它不能用C++20改进,我会很高兴地接受这个答案。

要求: 该函数必须是要在蹦床lambda中捕获的模板参数。蹦床的波长必须可以转换为函数指针。 它必须使用重载设置函数,如void somefunction(int& value)和 该函数应该能够是模板常量或不是。 应该支持Lambda。 请不要建议std::Function,这就是我所拥有的在函数可内联时的性能提高了10%。

它目前有效,但我相当自信我看到了改进这一点的技术Delegate<void(int&)>::Bind<TestStruct&, &TestStruct::somefunction>(testStruct, value);我只是目前无法弄清楚它们。

非常感谢

注意:是的,该值是在绑定函数中传递的,这只是为了说明,因为绑定函数是静态的。在我的代码中有一个绑定函数和一个调用函数。

推荐答案

我想改进这一点的原因是,由于实例类型必须由用户提供,因此非常容易出错。他必须弄清楚自己的实例是不是常量,是引用还是右值引用。当他将实例传递给绑定函数时,实际上所有这些信息都已经存在。

我是如何通过使用公共内部类来改进它的。事情可以变得更好,名字也可以更好,但这里是原则和如何使用它。

template <typename Signature>
class Delegate;

template <typename Ret, typename... Args>
struct Delegate<Ret(Args...)> {
    /* previous code from the question */

    // Don't mind the Trampoline type they are for the question in my real code this is a type ereased type.
    template <typename Instance_T, MemberFunctionConstOrNot_Ptr<Instance_T> fct>
    inline static Trampoline_T trampolineLambda = [](void* storage, Args&&... args) -> void {
        std::invoke(fct, *reinterpret_cast<std::remove_reference_t<Instance_T>*>(storage), std::forward<Args>(args)...);
    };

    template <typename Instance_T, MemberFunctionConstOrNot_Ptr<Instance_T> fct>
    inline static TrampolineConst_T trampolineLambdaConst = [](const void* storage, Args&&... args) -> void {
        std::invoke(fct, *reinterpret_cast<std::remove_reference_t<Instance_T>*>(storage), std::forward<Args>(args)...);
    };

    template <typename Instance_T>
    struct MemFnBinder
    {
        Delegate<Ret(Args...)>* m_delegate;

        Instance_T m_intance;

        template <MemberFunctionConstOrNot_Ptr<Instance_T> fct>
        void Bind()
        {
            using Type = std::remove_reference_t<Instance_T>;

            // Don't mind the fact that I am dealing with the constness like this. 
            // It is a by product of simplifying the code for the question. 
            constexpr bool IsConst = std::is_const_v<Type>;
            if constexpr (not IsConst) {
                m_delegate->m_trampoline = trampolineLambda<Instance_T, fct>;
            } else {
                m_delegate->m_trampolineConst = trampolineLambdaConst<Instance_T, fct>;
            }
        }
    };

    template <typename Instance_T>
    decltype(auto) GetMemFnBinder(Instance_T&& instance)
    {
        return MemFnBinder<Instance_T>{this, instance};
    }
};

如何使用它,使用与问题相同的TestStruct。也不考虑我正在创建Delegate<void(int&)>{}临时的,只是我不能将函数GetMemFnBinder设置为静态的,因为我做蹦床的方式。这对于设计模式是无关紧要的。

TestStruct testStruct;
const TestStruct testStructConst;
Delegate<void(int&)> delegate{};
delegate.GetMemFnBinder(testStruct).Bind<&TestStruct::somefunction>(); 
delegate.GetMemFnBinder(testStructConst).Bind<&TestStruct::somefunction>();
delegate.GetMemFnBinder(std::move(testStructConst)).Bind<&TestStruct::somefunction>();
delegate.GetMemFnBinder(TestStruct{}).Bind<&TestStruct::somefunction>();

我相信这比

Delegate<void(int&)>::Bind<TestStruct&, &TestStruct::somefunction>(testStruct);
Delegate<void(int&)>::Bind<const TestStruct&, &TestStruct::somefunction>(testStructConst);
Delegate<void(int&)>::Bind<TestStruct&&, &TestStruct::somefunction>(TestStruct{});

我同意我选择的名字可以改进。当我的大脑得到休息时,我会找到更好的名字。

这篇关于有什么方法可以改进这个Delegate&lt;void(int&amp;)&gt;::Bind&lt;TestStruct&amp;,&amp;TestStruct::SomeFunction&gt;(estStruct,Value)语法吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆