Is there a way to improve this Delegatelt;void(intamp;)gt;::Bindlt;TestStructamp;, amp;TestStruct::somefunctiongt;(testStruct, value) syntax?(有什么方法可以改进这个Delegatelt;void(intamp;)gt;::Bindlt;TestStructamp;,amp;TestStruct::SomeFunctiongt;(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<;void(int&;)>;::Bind<;TestStruct&;,&;TestStruct::SomeFunction>;(estStruct,Value)语法吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:有什么方法可以改进这个Delegate<;void(int&;)>;::Bind<;TestStruct&;,&;TestStruct::SomeFunction>;(estStruct,Value)语法吗?
基础教程推荐
- 您如何将 CreateThread 用于属于类成员的函数? 2021-01-01
- 什么是T&&(双与号)在 C++11 中是什么意思? 2022-11-04
- 如何定义双括号/双迭代器运算符,类似于向量的向量? 2022-01-01
- C++ 程序在执行 std::string 分配时总是崩溃 2022-01-01
- 运算符重载的基本规则和习语是什么? 2022-10-31
- C++,'if' 表达式中的变量声明 2021-01-01
- 调用std::Package_TASK::Get_Future()时可能出现争用情况 2022-12-17
- 如何在 C++ 中处理或避免堆栈溢出 2022-01-01
- C++ 标准:取消引用 NULL 指针以获取引用? 2021-01-01
- 设计字符串本地化的最佳方法 2022-01-01