2016-08-28 20 views
5

Ben bir yazım denetçim var. Bu listedeki her türdeki bir işlevi çağırmanın sonuçlarıyla bir tuple oluşturmak ve bunu argüman olarak başka bir functor'a kullanmak istiyorum. Böyle Yani bir şey:Çalışma zamanında işlevle tip uzmanı dönüştürün

template<typename F> 
struct function_traits; 

template<typename T, typename R, typename... Args> 
struct function_traits<R(T::*)(Args...) const> { 
    using return_type = R; 
    using param_types = std::tuple<Args...>; 
}; 

template<typename T> struct function_traits : public 
function_traits<decltype(&T::operator())> {}; 

template <typename T> 
T* get_arg(int id) 
{ 
    // Actual implementation omitted. Uses the id parameter to 
    // do a lookup into a table and return an existing instance 
    // of type T. 
    return new T(); 
} 

template <typename Func> 
void call_func(Func&& func, int id) 
{ 
    using param_types = function_traits<Func>::param_types>; 

    func(*get_arg<param_types>(id)...); // <--- Problem is this line 
} 

call_func([](int& a, char& b) { }, 3); 

sorun func(*get_arg<param_types>(id)...); aslında param_types beri derlemek olmamasıdır tuple değil, bir parametre paketidir. Derleyici bu hatayı üretir: "genişletmek için kullanılabilir bir parametre paketi yok".

func(*get_arg<int>(id), *get_arg<char>(id)); 

Ve argümanlar herhangi bir sayı için o işi yapmak: Bu hat genişletmek için Ne olmuş severdi olurdu olduğunu. Bu sonucu elde etmenin bir yolu var mı?

Bu soru benzer görünüyor ama sorunumu kendi başıma çözmüyor: "unpacking" a tuple to call a matching function pointer. Ben bir tür listesi var ve bundan ben fonksiyon argümanları olarak kullanılacak değerlerin listesini oluşturmak istiyorum. Değerler listesindeysem, onları genişletebilir ve bu soruda belirtildiği gibi işlevini çağırabilirdim, ama yapamam.

+0

call_func' içinde 'func' çağrısının beklenen sonucu nedir? Bütün argümanlar 'id'ye eşit olmalıdır? Senin örneğinde 'call_func ([] (int & a, char & b) {}, 3)' lambda argümanı ne olacak? –

+0

Kimlik parametresi gerçekten önemli değil. Benim kullandığım durumda, hangi T'nin geri döneceğini anlamak için onu get_arg içinde kullanıyorum. Lambda argümanları umarım, yukarıda yazdıklarıma benzer şekilde, tipte her tip için get_arg çağrısının sonucudur: 'func (* get_arg (id), * get_arg (id));' –

+0

Olası çoğaltması [bir eşleme işlev işaretçisi çağırmak için bir tuple açma] (http://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer) – TFM

cevap

1

Ne istediğinizi emin değilsiniz. Eğer bir yardımcı yapı kullanımını ve C++ 14 ile bir derleyici göze eğer

Ben ettik

..., call_func() içinde params_type parametreleri paketini genişletmek için nasıl bilmiyorum ama Aşağıdaki örnek, dönüş türü için destek ile hazırlandı.

#include <tuple> 

template<typename F> 
struct function_traits; 

template<typename T, typename R, typename... Args> 
struct function_traits<R(T::*)(Args...) const> { 
    using return_type = R; 
    using param_types = std::tuple<Args...>; 
}; 

template<typename T> struct function_traits : public 
function_traits<decltype(&T::operator())> {}; 

template <typename T, typename ... Args> 
T get_arg (std::tuple<Args...> const & tpl) 
{ return std::get<typename std::decay<T>::type>(tpl); } 

template <typename ...> 
struct call_func_helper; 

template <typename Func, typename Ret, typename ... Args> 
struct call_func_helper<Func, Ret, std::tuple<Args...>> 
{ 
    template <typename T, typename R = Ret> 
     static typename std::enable_if<false == std::is_same<void, R>::value, R>::type 
       fn (Func const & func, T const & t) 
     { return func(get_arg<Args>(t)...); } 

    template <typename T, typename R = Ret> 
     static typename std::enable_if<true == std::is_same<void, R>::value, R>::type 
       fn (Func const & func, T const & t) 
     { func(get_arg<Args>(t)...); } 
}; 

template <typename Func, 
      typename T, 
      typename R = typename function_traits<Func>::return_type> 
R call_func (Func const & func, T const & id) 
{ 
    using param_types = typename function_traits<Func>::param_types; 

    return call_func_helper<Func, R, param_types>::fn(func, id); 
} 

int main() 
{ 
    call_func([](int const & a, char const & b) { }, std::make_tuple(3, '6')); 

    return 0; 
} 

Bu yardımcı olur umarım.

+0

Güzel!Kafamı buna sarmak zorundayım ama bence ihtiyacım olan her şey bu. Ben lambda için bir uzmanlık olarak 'Func, Ret, std :: tuple >' kullanabileceğinizi şaşırıyorum (hoşça). Bunun yerine, 'R (T :: *) (Args ...) const' işlevinin 'function' işlevine benzemesi gerektiğini düşünürdüm. –