2012-08-09 17 views
25

在某些情況下,希望能夠類型擦除可調用對象(例如函數,函數指針,對象實例爲operator(),lambda,mem_fn)在Using Boost adaptors with C++11 lambdas中需要一個可複製分配和缺省構造的類型。推斷lambda或任意可調用的「make_function」的調用簽名

std::function將是理想的,但似乎沒有辦法自動確定什麼特徵與實例化類模板std::function。是否有一種簡單的方法來獲取任意可調用函數簽名和/或將其包裝在適當的實例化實例中(即函數模板make_function)?

具體來說,我正在尋找一個或其他

template<typename F> using get_signature = ...; 
template<typename F> std::function<get_signature<F>> make_function(F &&f) { ... } 

這樣make_function([](int i) { return 0; })回報std::function<int(int)>的。顯然,如果一個實例可調用多個簽名(例如,具有多於一個的模板或默認參數operator() s的對象),則預計不會有效。

Boost很好,雖然不太複雜的非Boost解決方案是首選。


編輯:回答我自己的問題。

+1

如果你只關心lambda表達式,然後是的,你可以得到它的工作。我建議不要這樣做 - 我懷疑在C++ 11中introspecting functors有些反模式。確保你確實需要'std :: function'。 – 2012-08-10 02:21:36

回答

27

,我想出了一個非常討厭的非圖書館解決方案,使用的事實,lambda表達式有operator()

template<typename T> struct remove_class { }; 
template<typename C, typename R, typename... A> 
struct remove_class<R(C::*)(A...)> { using type = R(A...); }; 
template<typename C, typename R, typename... A> 
struct remove_class<R(C::*)(A...) const> { using type = R(A...); }; 
template<typename C, typename R, typename... A> 
struct remove_class<R(C::*)(A...) volatile> { using type = R(A...); }; 
template<typename C, typename R, typename... A> 
struct remove_class<R(C::*)(A...) const volatile> { using type = R(A...); }; 

template<typename T> 
struct get_signature_impl { using type = typename remove_class< 
    decltype(&std::remove_reference<T>::type::operator())>::type; }; 
template<typename R, typename... A> 
struct get_signature_impl<R(A...)> { using type = R(A...); }; 
template<typename R, typename... A> 
struct get_signature_impl<R(&)(A...)> { using type = R(A...); }; 
template<typename R, typename... A> 
struct get_signature_impl<R(*)(A...)> { using type = R(A...); }; 
template<typename T> using get_signature = typename get_signature_impl<T>::type; 

template<typename F> using make_function_type = std::function<get_signature<F>>; 
template<typename F> make_function_type<F> make_function(F &&f) { 
    return make_function_type<F>(std::forward<F>(f)); } 

這個地方可以簡化或改進的任何想法?任何明顯的錯誤?

+0

+1。 什麼'get_signature_impl'布爾模板參數呢? – 2012-10-05 05:08:33

+0

@LeonidVolnitsky這完全沒有必要;我已將其刪除。我想我把'get_signature'作爲遞歸模板寫在那裏,但現在不需要。 – ecatmur 2012-10-05 08:07:36

+0

爲什麼把&decltype(&std :: remove_reference :: type :: operator())> :: type? – Guillaume07 2013-04-11 12:40:34

2

不可能。您可以將operator()的地址作爲的某些類型,但不能用於任意可調用的類型,因爲它可能有重載或模板參數。 AFAIK對於lambda表達式是否起作用確實沒有明確定義。

+0

好點,但我主要關心lambda,只有一個'operator()'存在。 – ecatmur 2012-08-09 23:10:09

+0

好吧,這當然不是很好的定義,我真的不確定甚至確定它存在。 – Puppy 2012-08-09 23:14:34

+5

5.1.2:5 * lambda表達式的閉包類型有一個公共內聯函數調用操作符[...] * – ecatmur 2012-08-09 23:16:29

0

對於非可變參數非通用captureless拉姆達功能以及簡單的免費功能,可以使用以下方法:

#include <iostream> 

#include <cstdlib> 

template< typename L, typename R, typename ...A > 
constexpr 
auto // std::function< R (A...) > 
to_function_pointer(L l, R (L::*)(A...) const) 
{ 
    return static_cast< R (*)(A...) >(l); 
} 

template< typename L, typename R, typename ...A > 
constexpr 
auto // std::function< R (A...) > 
to_function_pointer(L l, R (L::*)(A...)) // for mutable lambda 
{ 
    return static_cast< R (*)(A...) >(l); 
} 

template< typename L > 
constexpr 
auto 
to_function_pointer(L l) 
{ 
    return to_function_pointer(l, &L::operator()); 
} 

template< typename R, typename ...A > 
constexpr 
auto // std::function< R (A...) > 
to_function_pointer(R (* fp)(A...)) 
{ 
    return fp; 
} 

namespace 
{ 

void f() { std::cout << __PRETTY_FUNCTION__ << std::endl; } 

} 

int 
main() 
{ 
    to_function_pointer([]() { std::cout << __PRETTY_FUNCTION__ << std::endl; })(); 
    //to_function_pointer([&]() { std::cout << __PRETTY_FUNCTION__ << std::endl; })(); // can't cast from non-captureless lambda to function pointer 
    to_function_pointer([]() mutable { std::cout << __PRETTY_FUNCTION__ << std::endl; })(); 
    to_function_pointer(f)(); 
    to_function_pointer(&f)(); 
    return EXIT_SUCCESS; 
}