2014-09-30 104 views
2

假設我有一個std::function其作爲輸入T類型的N參數(這可以使用一些元編程魔術構造;見下文),其中N模板參數 。我想std::bind第一個參數構造一個函數與N-1參數(例如myBind<...>(someValue))。我想不出一個聰明的元編程技巧來做到這一點。有什麼建議麼?綁定到與未知數量的在C++參數起作用

Lambda function with number of arguments determined at compile-time

你可以寫一個模板n_ary_function與嵌套typedef類型。這種類型的可用於如下:

template <int N> class A { 
    typename n_ary_function<N, double>::type func; 
}; 

n_ary_function定義:

template <std::size_t N, typename Type, typename ...Types> 
struct n_ary_function { 
    using type = typename n_ary_function<N - 1, Type, Type, Types...>::type; 
}; 

template <typename Type, typename ...Types> 
struct n_ary_function<0, Type, Types...> { 
    using type = std::function<void(Types...)>; 
}; 
+2

你可以發佈你的代碼,建立'功能'? – 2014-09-30 20:57:39

+0

@PiotrS .:我已經把問題放在了問題中。 – parsiad 2014-09-30 20:58:16

回答

4

std::bind使用std::is_placeholder檢測佔位符,這意味着你可以編寫自己的佔位符由部分專業std::is_placeholderstd::bind使用:

template<int N> 
struct my_placeholder { static my_placeholder ph; }; 

template<int N> 
my_placeholder<N> my_placeholder<N>::ph; 

namespace std { 
    template<int N> 
    struct is_placeholder<::my_placeholder<N>> : std::integral_constant<int, N> { }; 
} 

這可以從一個整數獲取的佔位符。其餘的只是標準的整數序列絕招:

template<class R, class T, class...Types, class U, int... indices> 
std::function<R (Types...)> bind_first(std::function<R (T, Types...)> f, U val, std::integer_sequence<int, indices...> /*seq*/) { 
    return std::bind(f, val, my_placeholder<indices+1>::ph...); 
} 
template<class R, class T, class...Types, class U> 
std::function<R (Types...)> bind_first(std::function<R (T, Types...)> f, U val) { 
    return bind_first(f, val, std::make_integer_sequence<int, sizeof...(Types)>()); 
} 

Demostd::integer_sequence在技術上是C++ 14,但它很容易在C++ 11中實現 - 只需在SO上搜索即可。

+0

謝謝。我已經有了一個用於C++ 11的整數序列生成器,所以這個結果非常好。我也刪除了7-8行(在演示中)。 – parsiad 2014-10-01 14:30:44

2
#include <functional> 
#include <cstddef> 
#include <utility> 
#include <tuple> 

template <std::size_t N, typename Type, typename... Types> 
struct n_ary_function 
{ 
    using type = typename n_ary_function<N - 1, Type, Type, Types...>::type; 
}; 

template <typename Type, typename... Types> 
struct n_ary_function<0, Type, Types...> 
{ 
    using type = std::function<void(Types...)>; 
}; 

using placeholders_list = std::tuple<decltype(std::placeholders::_1) 
            , decltype(std::placeholders::_2) 
            , decltype(std::placeholders::_3) 
            , decltype(std::placeholders::_4) 
            , decltype(std::placeholders::_5) 
            , decltype(std::placeholders::_6) 
            , decltype(std::placeholders::_7) 
            , decltype(std::placeholders::_8) 
            , decltype(std::placeholders::_9) 
            , decltype(std::placeholders::_10) 
            >; 

template <typename F> 
struct arity; 

template <typename R, typename... Args> 
struct arity<std::function<R(Args...)>> 
{ 
    static constexpr std::size_t value = sizeof...(Args); 
}; 

template <typename F, typename T, std::size_t... Ints> 
auto binder(F f, T t, std::index_sequence<Ints...>) 
{ 
    return std::bind(f, t, 
      typename std::tuple_element<Ints, placeholders_list>::type{}...); 
} 

template <typename F, typename T> 
auto myBind(F f, T t) 
{ 
    return binder(f, t, std::make_index_sequence<arity<F>::value - 1>{}); 
} 

測試:

#include <iostream> 

void foo(int a, int b, int c, int d, int e) 
{ 
    std::cout << a << b << c << d << e << std::endl; 
} 

int main() 
{ 
    n_ary_function<5, int>::type f = foo; 
    n_ary_function<4, int>::type b = myBind(f, 1); 
    b(2, 3, 4, 5); 
} 

DEMO