2016-12-04 49 views
3

有幾個模板類與函數指針一起使用一個,兩個等參數。如何寫一個模板類而不是幾個?

template <typename A1, int(*func)(A1)> 
class Something1 
{ 
public: 
    static void f() 
    { 
     A1 a1; 
     // ... 
     int r = func(a1); 
     // ... 
    } 
}; 

template <typename A1, typename A2, int(*func)(A1, A2)> 
class Something2 
{ 
public: 
    static void f() 
    { 
     A1 a1; 
     A2 a2; 
     // ... 
     int r = func(a1, a2); 
     // ... 
    } 
}; 

如何編寫一個模板類,可以使用指針指向任意數量參數的函數?可能嗎?

回答

0

使用類/結構模板專業化,可以做類似你問的東西。

而不是你的SomethingN類,我已經開發了以下foo結構;我已經實現了一個bar()方法得到的Args...列表傳遞給func和接收了什麼方法baz(),並創建默認構造Args...func

#include <iostream> 

template <typename F, F> 
struct foo; 

template <typename ... Args, int(*func)(Args...)> 
struct foo<int(*)(Args...), func> 
{ 
    int bar (Args ... args) 
    { return func(args...); } 

    int baz() 
    { return func(Args{}...); } 
}; 


int func0() 
{ return 0; } 

int func1 (int) 
{ return 1; } 

int func2 (std::string const &, long) 
{ return 2; } 

int func3 (char, std::string const &, long) 
{ return 3; } 

int main() 
{ 
    foo<decltype(&func0), func0> f0; 
    foo<decltype(&func1), func1> f1; 
    foo<decltype(&func2), func2> f2; 
    foo<decltype(&func3), func3> f3; 

    std::cout << f0.bar() << std::endl;     // print 0 
    std::cout << f1.bar(3) << std::endl;     // print 1 
    std::cout << f2.bar("string", 2L) << std::endl;  // print 2 
    std::cout << f3.bar('c', "string", 2L) << std::endl; // print 3 

    std::cout << f0.baz() << std::endl; // print 0 
    std::cout << f1.baz() << std::endl; // print 1 
    std::cout << f2.baz() << std::endl; // print 2 
    std::cout << f3.baz() << std::endl; // print 3 
} 
+0

就個人而言,我也將有條件地提供一個助手宏(只有在包含頭文件之前定義了一些其他宏,例如'ENABLE_MAKE_FOO'時才定義),類似於'#define make_foo(func_)foo ',可用作'make_foo(func0)f0;'或'auto f0 = make_foo(func0){};' –

1

你無法定義僅有一個模板類模板參數並接受一個函數指針,其參數必須被推導出來。
要做到這一點,你必須使用這樣的事情:

template<typename F, F *func> 
struct S; 

template<typename R, typename... A, R(*f)(A...)> 
struct S<R(A...), f> {}; 

和一個漂亮的醜陋符號像這樣的:

S<decltype(f), &f> s; 

可能的替代方法是使用函數指針作爲參數傳遞給構造函數:

#include<type_traits> 
#include<utility> 

template<typename> 
struct S; 

template<typename R, typename... A> 
struct S<R(A...)> { 
    S(R(*f)(A...)): f{f} {} 
    R operator()(A... args) { return f(args...); } 

private: 
    R(*f)(A...); 
}; 

void g() {} 
int h(int) { return 0; } 

int main() { 
    S<void(void)> s1{&g}; 
    S<int(int)> s2{&h}; 
    s1(); 
    s2(42); 
} 

如果你想要去一點,並有一個更靈活的解決方案,你可以解決它也可以通過使用lambda表達式和工廠方法:

#include<type_traits> 
#include<utility> 

template<typename F> 
struct S: F { S(F &&f): F{std::forward<F>(f)} {} }; 

template<typename F> 
constexpr auto create(F &&f) 
-> decltype(S<typename std::decay<F>::type>{std::forward<F>(f)}) { 
    return S<typename std::decay<F>::type>{std::forward<F>(f)}; 
} 

void g() {} 
int h(int) { return 0; } 

int main() { 
    auto s1 = create([](){ g(); }); 
    auto s2 = create([](int i){ return h(i); }); 
    s1(); 
    s2(42); 
} 

作爲一個側面說明,如果你能使用C++ 14,最後一個片斷的語法變得更漂亮:

#include<type_traits> 
#include<utility> 

template<typename F> 
struct S: F { S(F &&f): F{std::forward<F>(f)} {} }; 

template<typename F> 
constexpr auto create(F &&f) { 
    return S<std::decay_t<F>>{std::forward<F>(f)}; 
} 

void g() {} 
int h(int) { return 0; } 

int main() { 
    auto s1 = create([](){ g(); }); 
    auto s2 = create([](auto&&... args){ return h(std::forward<decltype(args)>(args)...); }); 
    s1(); 
    s2(42); 
} 
相關問題