如果参数类型可转换,则将函数类型转换为不同
Cast function type to differ if types of arguments are convertable
我正在为可调用类型(函数指针、仿函数等)编写包装器 class。我想实现类似 std::function 的东西。
我从指向函数的指针定义构造函数:
template <typename Ret, typename... Args>
class function<Ret(Args...)>
{
public:
function(Ret (func)(Args...))
{
m_fn_ptr = func;
}
}
现在,假设我想像这样使用我的 class:
int int_function(int n)
{
return n;
}
function<int(short)> wrapper(&int_function); // compile error
尽管 short 可以隐式转换为 int 编译器无法推导出模板参数并调用适当的构造函数。
然后我试了这个:
template <typename FRet, typename... FArgs>
function(FRet (func)(FArgs...))
{
m_fn_ptr = static_cast<Ret (*f)(Args...)>(func);
}
但是我得到了无效的静态转换。
我该如何解决?
How can I fix that ?
创建时使用正确的类型 wrapper
。
而不是使用
function<int(short)> wrapper(&int_function);
使用
function<int(int)> wrapper(&int_function);
请记住,使用 int
和 short
实例化的 class 模板是非常不同的类型,不能相互转换。
template <typename T> struct Foo {};
Foo<int> a;
Foo<short> b = a; // Not OK.
Foo<short> c;
Foo<int> d = c; // Not OK.
您的 function
构造函数需要一个指向接受 short
而不是 int
的函数的指针。修复是为它提供这样的功能。最简单的方法是使用带有空捕获列表的 lambda,它可以隐式转换为函数指针:
function<int(short)> wrapper( [](short s) { return int_function(s); } );
super_func
是一个没有状态的函数对象,可以转换为任何兼容的调用签名。
template<class T>using type=T;
template<class Sig, Sig* func>
struct super_func;
template<class R, class...Args, R(*func)(Args...)>
struct super_func<R(Args...), func> {
using Sig = R(Args...);
using pSig = Sig*;
template<class R2, class...Args2, std::enable_if_t<
std::is_convertible<
std::result_of_t<pSig(Args2...)>,
R2
>{}
&& !std::is_same<R2, void>{},
bool
> =true>
constexpr operator type<R2(Args2...)>*() const {
return [](Args2...args)->R2{
return func(std::forward<Args2>(args)...);
};
}
template<class...Args2, std::enable_if_t<
std::is_same<
std::result_of_t<pSig(Args2...)>,
R
>{},
bool
> =true>
constexpr operator type<void(Args2...)>*() const {
return [](Args2...args)->void{
func(std::forward<Args2>(args)...);
};
}
constexpr operator pSig() const {
return func;
}
constexpr R operator()(Args...args)const{
return func(std::forward<Args>(args)...);
}
};
live example。 super_func
是无状态的。要在函数 foo 上使用它,请执行:
super_func< decltype(foo), &foo > super_foo;
你会得到一个可调用的无状态空对象,它的行为很像 foo
,除了你可以将它分配给一个指向任何兼容函数指针的指针并在编译时生成它 "on the fly" .
可以将 super_foo
提供给您的函数对象。
如果没有外部帮助,即时执行此操作是行不通的,因为我们需要 foo
成为真正静态的信息位。当它成为一个变量时,无状态地执行此操作为时已晚,因此我们不能使用 lambda 技巧(没有额外的 pvoid)为我们想要的确切签名生成函数指针。
你可以做一个宏:
#define SUPER(X) super_func< decltype(X), &X >{}
然后使用 function<double()> f(SUPER(foo));
创建您的 function
对象
另一种方法是存储额外的指针状态值,并创建 "the fastest possible delegate" 样式类型擦除。 (该术语可以在许多实现中的一种上用谷歌搜索,每一个都比上一个快)。
我正在为可调用类型(函数指针、仿函数等)编写包装器 class。我想实现类似 std::function 的东西。
我从指向函数的指针定义构造函数:
template <typename Ret, typename... Args>
class function<Ret(Args...)>
{
public:
function(Ret (func)(Args...))
{
m_fn_ptr = func;
}
}
现在,假设我想像这样使用我的 class:
int int_function(int n)
{
return n;
}
function<int(short)> wrapper(&int_function); // compile error
尽管 short 可以隐式转换为 int 编译器无法推导出模板参数并调用适当的构造函数。
然后我试了这个:
template <typename FRet, typename... FArgs>
function(FRet (func)(FArgs...))
{
m_fn_ptr = static_cast<Ret (*f)(Args...)>(func);
}
但是我得到了无效的静态转换。
我该如何解决?
How can I fix that ?
创建时使用正确的类型 wrapper
。
而不是使用
function<int(short)> wrapper(&int_function);
使用
function<int(int)> wrapper(&int_function);
请记住,使用 int
和 short
实例化的 class 模板是非常不同的类型,不能相互转换。
template <typename T> struct Foo {};
Foo<int> a;
Foo<short> b = a; // Not OK.
Foo<short> c;
Foo<int> d = c; // Not OK.
您的 function
构造函数需要一个指向接受 short
而不是 int
的函数的指针。修复是为它提供这样的功能。最简单的方法是使用带有空捕获列表的 lambda,它可以隐式转换为函数指针:
function<int(short)> wrapper( [](short s) { return int_function(s); } );
super_func
是一个没有状态的函数对象,可以转换为任何兼容的调用签名。
template<class T>using type=T;
template<class Sig, Sig* func>
struct super_func;
template<class R, class...Args, R(*func)(Args...)>
struct super_func<R(Args...), func> {
using Sig = R(Args...);
using pSig = Sig*;
template<class R2, class...Args2, std::enable_if_t<
std::is_convertible<
std::result_of_t<pSig(Args2...)>,
R2
>{}
&& !std::is_same<R2, void>{},
bool
> =true>
constexpr operator type<R2(Args2...)>*() const {
return [](Args2...args)->R2{
return func(std::forward<Args2>(args)...);
};
}
template<class...Args2, std::enable_if_t<
std::is_same<
std::result_of_t<pSig(Args2...)>,
R
>{},
bool
> =true>
constexpr operator type<void(Args2...)>*() const {
return [](Args2...args)->void{
func(std::forward<Args2>(args)...);
};
}
constexpr operator pSig() const {
return func;
}
constexpr R operator()(Args...args)const{
return func(std::forward<Args>(args)...);
}
};
live example。 super_func
是无状态的。要在函数 foo 上使用它,请执行:
super_func< decltype(foo), &foo > super_foo;
你会得到一个可调用的无状态空对象,它的行为很像 foo
,除了你可以将它分配给一个指向任何兼容函数指针的指针并在编译时生成它 "on the fly" .
可以将 super_foo
提供给您的函数对象。
如果没有外部帮助,即时执行此操作是行不通的,因为我们需要 foo
成为真正静态的信息位。当它成为一个变量时,无状态地执行此操作为时已晚,因此我们不能使用 lambda 技巧(没有额外的 pvoid)为我们想要的确切签名生成函数指针。
你可以做一个宏:
#define SUPER(X) super_func< decltype(X), &X >{}
然后使用 function<double()> f(SUPER(foo));
function
对象
另一种方法是存储额外的指针状态值,并创建 "the fastest possible delegate" 样式类型擦除。 (该术语可以在许多实现中的一种上用谷歌搜索,每一个都比上一个快)。