2016-04-08 44 views
7

我試圖創建一個通用包裝器函數,該函數將一個函數作爲模板參數,並將該函數作爲其參數使用相同的參數。例如:函數作爲模板參數的C++函數調用包裝器

template <typename F, F func> 
/* return type of F */ wrapper(Ts... Args /* not sure how to get Ts*/) 
{ 
    // do stuff 
    auto ret = F(std::forward<Ts>(args)...); 
    // do some other stuff 
    return ret; 
} 

該解決方案需要被強制轉換爲與相同類型func函數指針,這樣我可以將它傳遞給一個C API。換句話說,解決方案需要是一個功能而不是一個功能對象。最重要的是,我需要能夠在包裝函數中工作。

如果內嵌評論是不明確的,我希望能夠做到像下面這樣:

struct c_api_interface { 
    int (*func_a)(int, int); 
    int (*func_b)(char, char, char); 
}; 

int foo(int a, int b) 
{ 
    return a + b; 
} 

int bar(char a, char b, char c) 
{ 
    return a + b * c; 
} 

c_api_interface my_interface; 
my_interface.func_a = wrapper<foo>; 
my_interface.func_b = wrapper<bar>; 

我找了相關的帖子,發現這些,但他們都不是很什麼我正在努力。大多數這些帖子都涉及功能對象。我試圖做甚至可能嗎?

Function passed as template argument

Function wrapper via (function object) class (variadic) template

How does wrapping a function pointer and function object work in generic code?

How do I get the argument types of a function pointer in a variadic template class?

Generic functor for functions with any argument list

C++ Functors - and their uses

爲了迴應前兩個回答,我編輯了這個問題,以清楚地說明我需要能夠在包裝函數中進行工作。在調用包裝的函數)

回答

3
#include <utility> 
#include <iostream> 

struct c_api_interface { int (*func_a)(int, int); int (*func_b)(char, char, char); }; 
int foo(int a, int b) { return a + b; } 
int bar(char a, char b, char c) { return a + b * c; } 


template<typename Fn, Fn fn, typename... Args> 
typename std::result_of<Fn(Args...)>::type 
wrapper(Args... args) { 
    std::cout << "and ....it's a wrap "; 
    return fn(std::forward<Args>(args)...); 
} 
#define WRAPIT(FUNC) wrapper<decltype(&FUNC), &FUNC> 

int main() { 
    c_api_interface my_interface; 
    my_interface.func_a = WRAPIT(foo); 
    my_interface.func_b = WRAPIT(bar); 

    std:: cout << my_interface.func_a(1,1) << std::endl; 
    std:: cout << my_interface.func_b('a','b', 1) << std::endl; 

    return 0; 
} 

看到http://rextester.com/ZZD18334

+0

謝謝!我將它改爲接受的答案,因爲它比@TC短,只使用函數而不是結構,使用'std :: forward',(作爲意見)更容易理解,因爲你沒有使用模板參數專門化。 – Eric

+0

儘管我不得不承認std :: forward只是在那裏,因爲我嘗試了一些可以在MSVC下編譯的東西,然後認爲「啊擰它,不會發生......但是,嘿,繼續前進」;-) – VolkerK

+0

什麼是爲wrapper聲明一個別名的正確方法,它看起來像一個正常的函數來調用?就像'使用a_wrapped = wrapper ;'(但這個不起作用)。 – eudoxos

0

你可能需要像

template <typename F> 
class Wrapper { 
public: 
    Wrapper(F *func) : function(func) {} 
    operator F*() { return function; } 
    F *function; 
}; 

,你可以使用像void (*funcPtr)(int) = Wrapper<void(int)>(&someFunction);

+0

我欣賞的迴應,但這並不做什麼,我要求在原崗位。在你的解決方案中,如果我調用'funcPtr()',它會調用'someFunction'。我希望它調用一個在調用'someFunction'之前和之後執行一些工作的函數。 – Eric

+1

@Eric,現在我明白你想要什麼,不明白你爲什麼要這麼辛苦。Lambda函數沒有捕獲可轉換爲c函數指針:'void(* funcPtr)(int)= [](int a){/ * smth * /};' - 調用包裝函數和lambda中的前後例程 –

+0

起初嘗試過。我相信只有當lambda函數不捕獲函數時,lambdas才能被轉換爲函數指針,並且爲了使這個通用函數我需要編寫一個lambda函數來捕獲它將要調用的函數,但也許有一種方法可以使我缺少的工作成爲可能。 – Eric

0

我認爲這將是做簡潔的方式前後修改一些全局狀態你想要什麼:

template <typename F> 
F* wrapper(F* pFunc) 
{ 
    return pFunc; 
} 

,並使用它像這樣:

my_interface.func_a = wrapper(foo); 
my_interface.func_a(1, 3); 
+0

感謝您的回覆,但這不符合我的要求。在我調用包裝函數(在本例中爲'foo')之前和之後,我需要能夠在包裝函數中做一些工作。因此包裝函數需要具有與包裝函數**相同的函數簽名。 – Eric

+0

我不確定你可以從模板參數中檢索簽名(即'Ts ... Args'),但是你可以將它們保存爲延期調用,如[顯示](http://stackoverflow.com/questions/15537817/c然後在'Wrapper :: operator()'中,在保存的參數調用底層函數之前和之後做一些事情 –

7
template<class F, F f> struct wrapper_impl; 
template<class R, class... Args, R(*f)(Args...)> 
struct wrapper_impl<R(*)(Args...), f> { 
    static R wrap(Args... args) { 
     // stuff 
     return f(args...); 
    } 
}; 

template<class F, F f> 
constexpr auto wrapper = wrapper_impl<F, f>::wrap; 

用作wrapper<decltype(&foo), foo>

+0

非常感謝,這工作完美! :)對於其他人:變量模板是我相信的一個C++ 14功能,因此可能無法在所有編譯器上使用。我定義了一個宏#define wrapper(func)wrapper_impl :: wrap',它們完成了大致相同的事情。 – Eric

+0

這是否可以適應可選參數?這意味着包裝函數中可選的參數在包裝中也是可選的。在這個變體中,必須指定所有參數。 – eudoxos

0

您可以嘗試類似的東西(醜,但工程)

#include <iostream> 
#include <functional> 

struct wrapper_ctx 
{ 
    wrapper_ctx() 
    { 
    std::cout << "Before" << std::endl; 
    } 
    ~wrapper_ctx() 
    { 
    std::cout << "after" << std::endl; 
    } 
}; 

template <typename F, typename... Args> 
auto executor (F&& f, Args&&... args) -> typename std::result_of<F(Args...)>::type 
{ 
    wrapper_ctx ctx; 
    return std::forward<F>(f)(std::forward<Args>(args)...); 

} 

template <typename F> 
class wrapper_helper; 


template<typename Ret, typename... Args> 
class wrapper_helper <std::function<Ret(Args...)>> 
{ 
    std::function<Ret(Args...)> m_f; 
public: 
    wrapper_helper(std::function<Ret(Args...)> f) 
     : m_f(f) {} 
    Ret operator()(Args... args) const 
    { 
    return executor (m_f, args...); 
    } 
}; 

template <typename T> 
wrapper_helper<T> wrapper (T f) 
{ 
    return wrapper_helper <T>(f); 
} 


int sum(int x, int y) 
{ 
    return x + y; 
} 


int main (int argc, char* argv []) 
{ 

    std::function<int(int, int)> f = sum; 
    auto w = wrapper (f); 

    std::cout << "Executing the wrapper" << std::endl; 
    int z = w(3, 4); 

    std::cout << "z = " << z << std::endl; 
}