2013-02-09 74 views
3

我有一個boost ::變種,我想只執行,如果變體是一種特殊類型的函子,所以我做了這個功能:如何使用lambda在std :: function參數中推導出模板類型?

template<typename T, typename Variant> 
void if_init(Variant& opt_variant, std::function<void(T)> functor){ 
    if(auto* ptr = boost::get<T>(&opt_variant)){ 
     functor(*ptr); 
    } 
} 

這工作不錯,但我想T型被推斷,這樣我可以寫:

if_init(b, [](double var){ std::cout << "I'm double and set" << std::endl; }); 

但類型不會推導出:

type_inference.cpp:19:5: error: no matching function for call to 'if_init' 
    if_init(b, [](double var){ std::cout << "I'm double and set" << std::endl; }); 
    ^~~~~~~ 
type_inference.cpp:10:6: note: candidate template ignored: failed template argument deduction 
    void if_init(Variant& opt_variant, std::function<void(T)> functor){ 

如果我寫:

if_init<double>(b, [](double var){ std::cout << "I'm double and set" << std::endl; }); 

它運作良好。

有沒有辦法讓T型被推斷出來?我只想輸入一次T.這裏的類型很短,但在實際情況下,類型很長。

我正在使用CLang 3.2。

以下是完整的測試用例(第一次調用編譯沒有第二個):

#include <iostream> 
#include <functional> 
#include <boost/variant.hpp> 

typedef boost::variant<int, double> Test; 

template<typename T, typename Variant> 
void if_init(Variant& opt_variant, std::function<void(T)> functor){ 
    if(auto* ptr = boost::get<T>(&opt_variant)){ 
     functor(*ptr); 
    } 
} 

int main(){ 
    Test b = 1.44; 

    if_init<double>(b, [](double var){ std::cout << "I'm double and set" << std::endl; }); 
    if_init(b, [](int var){ std::cout << "I'm int and set" << std::endl; });  

    return 0; 
} 

回答

6

我建議你認爲std::function<Sig>爲符合Sig作爲簽名的任何一個函數對象的容器 - 和可隨時更換。這個功能非常適用於例如因爲這樣的容器可以容納不同的類型的仿函數。

在你的情況,因爲你只關心只有一個函數,你真的不需要std::function<Sig>的功能。因此,我建議你宣佈你的函數模板,像這樣:

template<typename T, typename Variant, typename Functor> 
void if_init(Variant& opt_variant, Functor functor); 

如果你擔心,這不會傳達Functor必須符合void(T)簽名,請注意std::function<Sig>執行,要麼:雖然顯然你結束了一個編譯錯誤,這不是一個不錯的。它計劃被改變(也許你的實現也是這樣),但是改成了另外一種錯誤。對你的情況仍然沒有幫助。

我個人使用模板別名(in the template parameter list)來記錄和強制仿函數應符合。這最終看起來像:

// Documents that e.g. long l = std::forward<Functor>(functor)(42.) 
// should be a valid expression -- a functor that returns int would 
// also be accepted. 
// Triggers a hard-error (typically a static_assert with a nice message) 
// on violation. 
template<typename Functor, Requires<is_callable<Functor, long(double)>>...> 
R foo(Functor functor); 

// Documents that this function template only participates in overload resolution 
// if the functor conforms to the signature. 
// Does not trigger a hard-error (necessary by design); if everything goes right 
// then another overload should be picked up -- otherwise an error of the kind 
// 'no matching overload found' is produced 
template<typename Functor, EnableIf<is_callable<Functor, long(double)>>...> 
R bar(Functor functor); 

至於你確切問題,C++的規則不允許在你的情況可以推斷模板參數。如果是「問題」,那真的不是一個容易解決的問題。你可以在這裏找到more information

+0

好的,我不知道std :: function 沒有強制執行:(但是,如果我只使用typename Functor,它不會改變T不會被推斷的事實,對吧? – 2013-02-09 03:34:22

+0

@BaptisteWicht是。在這種情況下,你可以要求'Functor'是單形的並且提取它的單個參數類型。這不是我通常做的事情(我真的試圖避免檢查函子,因爲這對於多態函數不起作用),我無法想象一個特質能夠完成這項工作。 – 2013-02-09 03:51:11

相關問題