2014-09-25 66 views
1

我一直在搜索SO和其他論壇尋找一種方法來確定lambda的參數和返回類型,然後對這些參數進行操作,以便對回購進行類型查找已經實例化的對象。重點是創建一種方法來對某些任意定義的lambda表達式執行依賴注入。舉例來說,如果我有類似如下:在模板類型上編譯時間循環

auto lambda = [] (MyObject o) -> string { return o.name(); }; 

我能確定的參數類型的拉姆達,並查找MyObject類型的相應的對象,然後調用lambda傳遞一個對象「自動地」。

到目前爲止,我已經找到方法來確定lambda表達式參數列表類型,並通過使用以下模板返回類型:

template <typename T> 
struct function_traits 
    : public function_traits<decltype(&T::operator())> 
{}; 
// For generic types, directly use the result of the signature of its 'operator()' 

template <typename ClassType, typename ReturnType, typename... Args> 
struct function_traits<ReturnType(ClassType::*)(Args...) const> 
    // we specialize for pointers to member function 
{ 
    enum { arity = sizeof...(Args) }; 
    // arity is the number of arguments. 

    typedef ReturnType result_type; 

    template <size_t i> 
    struct arg 
    { 
     typedef typename std::tuple_element<i, std::tuple<Args...>>::type type; 
     // the i-th argument is equivalent to the i-th tuple element of a tuple 
     // composed of those arguments. 
    }; 
}; 

我在this發現SO發佈(很整齊)。

現在,我願意做的事情,是實現某種編譯時當量以下的:

// first get the type of the lambda using the above 'function_traits' template 
typedef function_traits<decltype(lambda)> traits; 
// now iterate over the traits and get the type of each argument, then print out the type name 
for (size_t i = 0u; i < size_t(traits::arity); ++i) 
{ 
    // The point to focus on here is `traits::args<i>::type` 
    std::cout << typeid(traits::args<i>::type).name() << std::end; 
} 

我上面張貼什麼是不可能的。上面的代碼中的問題是,i不是一個常量,而是在運行時進行評估,而不是編譯時間(評估此模板魔法的其餘部分)。我嘗試了一些不同的方法來嘗試找出解決方法(其中的模板遞歸),但是我一直無法找到完全符合我需要的解決方案。

所以,我的問題的根源真的是,你如何「迭代」模板?我是TMP的新手,並且從運行時轉變爲編譯時邏輯一直具有挑戰性。如果任何人有一些建議,對於一個很棒的新手來說。

+1

循環一般你可以acc用下面迭代的'template class Loop {...}'來代表'Loop ',並使用專門的'template class Loop {...}'來終止的情況下,但我不得不深入探討這個問題,以便弄清楚如何將其應用於這種情況。 – cdhowie 2014-09-25 20:13:06

+0

這個問題有兩種典型的方法:使用索引技巧進行遞歸和包擴展。你不會告訴我們遞歸有什麼問題,或者不幸的是你用遞歸嘗試了什麼。有關指數技巧,請參閱http://stackoverflow.com/a/7858971 – dyp 2014-09-25 20:25:25

+0

你甚至可以在SO上找到幾個標題爲「迭代遍歷元組」或類似的問題,例如: http://stackoverflow.com/q/1198260 – dyp 2014-09-25 20:27:29

回答

1

用C++ 14,你可以這樣做:

namespace detail 
{ 
    template <typename T, std::size_t ... Is> 
    void display(std::index_sequence<Is...>) 
    { 
     std::initializer_list<int>{((std::cout << typeid(typename T::template arg<Is>::type).name() << std::endl), 0)...}; 
    } 

} 

template <typename T> 
void display() 
{ 
    detail::display<T>(std::make_index_sequence<T::arity>()); 
} 

並使用它:

using traits = function_traits<decltype(lambda)>; 

display<traits>(); 

Live example

如果你堅持用C++ 11,有很多地方找到執行make_index_sequenceindex_sequence

+0

+1感謝您的回答,但這並不完美。它比我想要的更接近我所要做的,但我正在尋找一種方法來獲取lambda中每個參數的類型,以便我可以進行類型查找。我可能會誤導你我的使用示例。不過,我會深入挖掘'index_sequence'! – pje 2014-09-26 21:55:53