Defer/cancel 执行函数并分析它们的参数
Defer/cancel execution of functions and analyze their arguments
我正在尝试编写外部绘图调用优化,为此我需要收集钩子调用,存储它们的参数以便稍后分析它们。
我已经能够进行延迟调用和一些可读的参数,存储在 tuple
中,但我需要从基础 class 中读取参数,并且在彻底谷歌搜索后我找不到任何适用的东西。
我将主要使用 IDelegateBase
数组,将它们转换为具有完整签名的 Delegate<...>
会非常不方便,因为我通常只会读取一个参数。因此,我需要 IDelegateBase
中的 virtual
模板化方法,这将是 return 第 n 个参数。但是虚拟模板化方法是不可能的,所以我想我可能必须在基 class 中有模板化方法,这将调用非模板 (boost::any
?) 虚拟方法并转换它的结果,我想。但是,无论如何,我无法通过运行时变量从 tuple
获取第 n 个元素。
#include <functional>
#include <iostream>
class IDelegateBase
{
public:
virtual void invoke() { }
};
template <typename T, typename... Args>
class Delegate : public IDelegateBase
{
private:
void (*_f)(Args...);
std::tuple<Args...> _args;
public:
Delegate(T& f, Args &...args)
: _f(f), _args(args...) { }
void invoke() final
{
std::apply(_f, _args);
}
};
void a() { std::cout << "a called;\n"; }
void b(int x) { std::cout << "b called with " << x << "\n"; }
void c(int x, float y) { std::cout << "c called with " << x << ", " << y << "\n"; }
int main()
{
IDelegateBase* d = new Delegate(a);
d->invoke();
int i = 42;
d = new Delegate(b, i);
d->invoke();
i = 21;
float f = 0.999;
d = new Delegate(c, i, f);
d->invoke();
// I need something like this:
auto test = d->getArgument<float>(1);
};
更新:
带有类型检查的最终解决方案:https://godbolt.org/z/xeEWTeosx
您可以提供一个返回 void*
的虚函数并在模板中使用它,但类型安全性会付之东流:如果您 ever 类型错误,你最终会得到未定义的行为。
要使用索引获取元素,您可以使用递归辅助模板,该模板在每次递归调用时与一个索引进行比较。
class IDelegateBase
{
public:
virtual void invoke() { }
template<class T>
T const& getArgument(size_t index) const
{
return *static_cast<T const*>(getArgumentHelper(index));
}
protected:
virtual void const* getArgumentHelper(size_t index) const = 0;
};
template <typename T, typename... Args>
class Delegate : public IDelegateBase
{
private:
void (*_f)(Args...);
std::tuple<Args...> _args;
public:
Delegate(T& f, Args &...args)
: _f(f), _args(args...) { }
void invoke() final
{
std::apply(_f, _args);
}
protected:
void const* getArgumentHelper(size_t index) const override
{
return GetHelper<0>(index, _args);
}
private:
template<size_t index>
static void const* GetHelper(size_t i, std::tuple<Args...> const& args)
{
if constexpr (sizeof...(Args) > index)
{
if (index == i)
{
return &std::get<index>(args);
}
else
{
return GetHelper<index + 1>(i, args);
}
}
else
{
throw std::runtime_error("index out of bounds");
}
}
};
这里需要使用if constexpr
,因为如果使用超出范围的元组索引,std::get
将无法编译。
我正在尝试编写外部绘图调用优化,为此我需要收集钩子调用,存储它们的参数以便稍后分析它们。
我已经能够进行延迟调用和一些可读的参数,存储在 tuple
中,但我需要从基础 class 中读取参数,并且在彻底谷歌搜索后我找不到任何适用的东西。
我将主要使用 IDelegateBase
数组,将它们转换为具有完整签名的 Delegate<...>
会非常不方便,因为我通常只会读取一个参数。因此,我需要 IDelegateBase
中的 virtual
模板化方法,这将是 return 第 n 个参数。但是虚拟模板化方法是不可能的,所以我想我可能必须在基 class 中有模板化方法,这将调用非模板 (boost::any
?) 虚拟方法并转换它的结果,我想。但是,无论如何,我无法通过运行时变量从 tuple
获取第 n 个元素。
#include <functional>
#include <iostream>
class IDelegateBase
{
public:
virtual void invoke() { }
};
template <typename T, typename... Args>
class Delegate : public IDelegateBase
{
private:
void (*_f)(Args...);
std::tuple<Args...> _args;
public:
Delegate(T& f, Args &...args)
: _f(f), _args(args...) { }
void invoke() final
{
std::apply(_f, _args);
}
};
void a() { std::cout << "a called;\n"; }
void b(int x) { std::cout << "b called with " << x << "\n"; }
void c(int x, float y) { std::cout << "c called with " << x << ", " << y << "\n"; }
int main()
{
IDelegateBase* d = new Delegate(a);
d->invoke();
int i = 42;
d = new Delegate(b, i);
d->invoke();
i = 21;
float f = 0.999;
d = new Delegate(c, i, f);
d->invoke();
// I need something like this:
auto test = d->getArgument<float>(1);
};
更新: 带有类型检查的最终解决方案:https://godbolt.org/z/xeEWTeosx
您可以提供一个返回 void*
的虚函数并在模板中使用它,但类型安全性会付之东流:如果您 ever 类型错误,你最终会得到未定义的行为。
要使用索引获取元素,您可以使用递归辅助模板,该模板在每次递归调用时与一个索引进行比较。
class IDelegateBase
{
public:
virtual void invoke() { }
template<class T>
T const& getArgument(size_t index) const
{
return *static_cast<T const*>(getArgumentHelper(index));
}
protected:
virtual void const* getArgumentHelper(size_t index) const = 0;
};
template <typename T, typename... Args>
class Delegate : public IDelegateBase
{
private:
void (*_f)(Args...);
std::tuple<Args...> _args;
public:
Delegate(T& f, Args &...args)
: _f(f), _args(args...) { }
void invoke() final
{
std::apply(_f, _args);
}
protected:
void const* getArgumentHelper(size_t index) const override
{
return GetHelper<0>(index, _args);
}
private:
template<size_t index>
static void const* GetHelper(size_t i, std::tuple<Args...> const& args)
{
if constexpr (sizeof...(Args) > index)
{
if (index == i)
{
return &std::get<index>(args);
}
else
{
return GetHelper<index + 1>(i, args);
}
}
else
{
throw std::runtime_error("index out of bounds");
}
}
};
这里需要使用if constexpr
,因为如果使用超出范围的元组索引,std::get
将无法编译。