2015-04-12 62 views
2

我正在为可调用类型(指向函数,函数等的指针)编写包装类。我想实现类似std :: function的东西。如果参数类型可转换,Cast函数类型会有所不同

我定义构造函数从函数指针:

template <typename Ret, typename... Args> 
class function<Ret(Args...)> 
{ 
public: 
    function(Ret (func)(Args...)) 
    { 
     m_fn_ptr = func; 
    } 
} 

现在,让我们假设,我想用我的阶级是这样的:

int int_function(int n) 
{ 
    return n; 
} 

function<int(short)> wrapper(&int_function); // compile error 

尽管短期是隐式可转换成int编译器不能推导模板参数并调用适当的构造函数。

然后我想这:

template <typename FRet, typename... FArgs> 
function(FRet (func)(FArgs...)) 
{ 
    m_fn_ptr = static_cast<Ret (*f)(Args...)>(func); 
} 

但我得到无效的静态浇铸。

我该如何解决这个问题?

+0

如果你的函数类可以包含任意的可调用对象(如'std :: function'),这个特性是免费的。 – sbabbi

+0

我想我可以实现这种类型的擦除成语,但有没有另一种解决方案? (因为类型擦除的经典实现将导致我动态分配内存) – eucpp

+0

@EvgeniyMoiseenko嗯,你可以选择只接受函数指针并将它们保存在一个'void *'中。 – Columbo

回答

1

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, class=std::enable_if_t< 
    std::is_convertible< 
     std::result_of_t<pSig(Args2...)>, 
     R2 
    >{} 
    && !std::is_same<R2, void>{} 
    >> 
    constexpr operator type<R2(Args2...)>*() const { 
    return [](Args2...args)->R2{ 
     return func(std::forward<Args2>(args)...); 
    }; 
    } 
    template<class...Args2, class=std::enable_if_t< 
    std::is_same< 
     std::result_of_t<pSig(Args2...)>, 
     R 
    >{} 
    >> 
    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。 A super_func是无状态的。要使用它的函数foo,做到:

super_func< decltype(foo), &foo > super_foo; 

,你会得到一个可调用无状态空的对象,它的行为很像0​​做,除非你可以把它分配给一个指针到任何兼容的函数指针,它产生它在编译时“即时”。

A super_foo可以喂给你的功能对象。

没有外部帮助,在飞行中这样做不起作用,因为我们需要foo成为一个真正的静态位信息。当它成为一个变量的时候,这种无状态的做法为时已晚,所以我们不能使用lambda技巧(没有额外的pvoid)为我们想要的确切签名生成一个函数指针。

你可以做一个宏:

#define SUPER(X) super_func< decltype(X), &X >{} 

,然后用function<double()> f(SUPER(foo));


创建function对象的另一种方法是存储一个额外的指针的价值状态,创造“以最快的速度代表“式擦除。 (该术语可以用于许多实现中的一个,每个实现都比上一个更快)。

0

我该如何解决这个问题?

创建时使用正确的类型wrapper

而不是使用

function<int(short)> wrapper(&int_function); 

使用

function<int(int)> wrapper(&int_function); 

记得用intshort实例化类模板有很大的不同类型和不可转换到对方。

template <typename T> struct Foo {}; 

Foo<int> a; 
Foo<short> b = a; // Not OK. 

Foo<short> c; 
Foo<int> d = c; // Not OK. 
+2

这基本上忽略了这个问题。 – Yakk

0

function构造函数需要一个指针,需要一个short,而不是一个int的功能。解决方法是提供这样的功能。要做到这一点,最简单的方法是使用lambda一个空捕获名单,这是隐式转换为一个函数指针:

function<int(short)> wrapper([](short s) { return int_function(s); }); 
相关问题