2015-04-12 65 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); }); 
相關問題