2015-11-05 22 views
5

因此,假設我有一個類,它包含功能對象,並在構造函數調用中傳遞參數,它將在某個時間傳遞給功能對象後來。喜歡的東西:Variadic模板 - 我如何創建類型,存儲傳遞的參數

class Binder{ 
public: 
    Binder(functional_object, listOfParameters); 
    callFunctionalObject(); // calls functional object with given list of parameters 
}; 

之前C++ 11我無法使用可變參數模板,所以一個會做:

struct none{}; 

template <typename T1, typename T2=none, typename T3=none> 
class Binder{ 
public: 
    Binder(T1 functionalObject, T2 arg1=none(), T3arg3=none()); 
    void callFunctionalObject(); 
private: 
    T1 m_functionalObject; 
    T2 m_arg1; 
    T3 m_arg2; 
}; 

callFunctionalobject可以實現如下:

template<typename T1, typename T2, typename T3> 
void Binder<T1,T2,T3>::callFunctionalObject(){ 
    callImpl(m_functionalObject, m_arg1, m_arg2); 
} 

callImpl將被重載以識別類型爲none的對象以將適量的參數傳遞給功能對象。

現在切換到C++ 11我不知道如何實現這一事實,在私人部分我有成員,我可以直接訪問。

任何人都可以解釋我的方式,我可以使用C++ 11或C++ 14做同樣的事情嗎?

回答

7

你應該存儲一個std::function和一個std::tuple,然後調用該元組上的函數。

這裏工作C++ 14溶液

#include <iostream> 
#include <functional> 

template<typename T1, typename ...T> 
class Binder 
{ 
public: 
    Binder(std::function<T1(T...)> f, std::tuple<T...> t) : m_functional_obj(f), m_parameters(t) {} 

    template<std::size_t ...I> 
    T1 callImpl(std::index_sequence<I...>) 
    { 
     return m_functional_obj(std::get<I>(m_parameters)...); 
    } 

    T1 callFunctionalObject() 
    { 
     return callImpl(std::index_sequence_for<T...>{}); 
    } 
private: 
    std::function<T1(T...)> m_functional_obj; 
    std::tuple<T...>  m_parameters; 
}; 

int test(int i) 
{ 
    std::cout << "test(" << i << ")" << std::endl;  
    return i + 1; 
} 

int main() 
{ 
    Binder<int,int> bibi(test, std::make_tuple<int>(2)); 
    auto res = bibi.callFunctionalObject(); 
    std::cout << "res is " << res << std::endl; 
} 

Live code

+2

我想到了這樣的事情,但不會functionalObject然後在參數代替參數正常名單得到一個touple? – DawidPi

+2

解壓縮tuple參數需要一點點工作,試圖爲您獲得實時代碼解決方案:) – coincoin

+1

@DawidPi更新了一個C++ 14解決方案,使用'std :: index_sequence' – coincoin

2

最簡單的方法是使用std::bind存儲與已經設定的參數的std::function對象:

class Binder{ 
public: 
    template <typename T1, typename... T2> 
    Binder(T1 functionalObject, T2... args) : f(std::bind(functionalObject, args...)) {} 
    void callFunctionalObject() { f(); } 
private: 
    std::function<void()> f; 
}; 

void foo(int n, std::string s) { 
    std::cout << n << " " << s << std::endl; 
} 

int main() 
{ 
    Binder b(foo, 42, "test"); 
    b.callFunctionalObject(); 
} 

如果你需要更先進的東西,那麼你可能需要存儲函數的參數在std::tuple中,然後使用一些模板魔法來解開它,但是請指出在問題中你確切需要什麼。

P.S.又見"unpacking" a tuple to call a matching function pointer

+0

好了std :: bind好像很簡單,但我仍然不知道這背後有什麼樣的機制。我應該嘗試尋找std :: bind實現。我正在尋找的是與使用Variadic模板的代碼給出n相同的功能,但更靈活(從開始就沒有設置最大數量的參數)。 – DawidPi

+1

我不認爲你需要模板參數,你可以使構造函數成爲模板,人們可以使用'Binder b(foo,32,「test」);'。 – SirGuy

+0

@GuyGreer,實際上已更新 – Petr

4

我的例子:

// Indices 
template <std::size_t... Is> 
struct Indices {}; 

template <std::size_t N, std::size_t... Is> 
struct BuildIndices : BuildIndices <N - 1, N - 1, Is...> {}; 

template <std::size_t... Is> 
struct BuildIndices<0, Is...> : Indices <Is...> {}; 

template<class FuncObject, class ... T> 
class Binder 
{ 
public: 
    Binder(FuncObject funcObject, T... args) 
     : m_funcObject(funcObject), m_arguments(std::make_tuple(args...)) 
    { 
    } 

    void Call() 
    { 
     DoCall(BuildIndices<sizeof ... (T)> {}); 
    } 

private: 
    template<size_t... Ind> 
    void DoCall(Indices<Ind...>) 
    { 
     return m_funcObject(std::get<Ind>(m_arguments)...); 
    } 

    FuncObject m_funcObject; 
    std::tuple<T...> m_arguments; 
}; 

void Foo(int, char) 
{ 
} 

int main() 
{ 
    Binder<void(*)(int, char), int, char> f(Foo, 1, 'd'); 
    f.Call(); 

    return 0; 
} 
+1

這很好,再加上在C++ 14中,你不再需要自己的'Indices'和'BuildIndices'類。 – SirGuy

相關問題