2013-01-18 47 views
1

以下是我經常使用的可愛小模板。簡單地告訴我,如果給定的元素是一個集合的成員(其本身必須與find_if模板兼容):如何改進此模板以接受VS2012中的lambdas

// returns true if a given collection contains the given element 
// NOTE: This is NOT optimized for associative containers! 
template <typename ELEMENT, typename COLLECTION, typename PREDICATE> 
bool contains(const COLLECTION & collection, ELEMENT element, PREDICATE predicate) 
{ 
    return collection.end() != std::find_if(collection.begin(), collection.end(), boost::bind(predicate, element, _1)); 
} 

我發現,VC2012不太願意,如果我嘗試使用lambda作謂語:

if (!contains(specs, str, [] (CString pathname, CString pattern) { return AsBool(PathMatchSpec(pathname, pattern)); })) 
    continue; 

VS2012SP1吐出了上述情況如下:

1>c:\users\steve\projects\cimex cad-cam\15.0\3rd party\boost\boost\bind\bind.hpp(69): error C2039: 'result_type' : is not a member of 'CMacroInterpreter::GetDirectoryOf::<lambda_60eac39ee69a5bdc77e08d06d79ae4c4>' 
1>   c:\users\steve\projects\cimex cad-cam\15.0\cimex application\cimcad\macro directory.cpp(166) : see declaration of 'CMacroInterpreter::GetDirectoryOf::<lambda_60eac39ee69a5bdc77e08d06d79ae4c4>' 
1>   c:\users\steve\projects\cimex cad-cam\15.0\3rd party\boost\boost\bind\bind_template.hpp(15) : see reference to class template instantiation 'boost::_bi::result_traits<R,F>' being compiled 
1>   with 
1>   [ 
1>    R=boost::_bi::unspecified, 
1>    F=CMacroInterpreter::GetDirectoryOf::<lambda_60eac39ee69a5bdc77e08d06d79ae4c4> 
1>   ] 
1>   c:\users\steve\projects\cimex cad-cam\15.0\mfc toolbox\miscellaneous.h(360) : see reference to class template instantiation 'boost::_bi::bind_t<R,F,L>' being compiled 
1>   with 
1>   [ 
1>    R=boost::_bi::unspecified, 
1>    F=CMacroInterpreter::GetDirectoryOf::<lambda_60eac39ee69a5bdc77e08d06d79ae4c4>, 
1>    L=boost::_bi::list2<boost::_bi::value<CString>,boost::arg<1>> 
1>   ] 
1>   c:\users\steve\projects\cimex cad-cam\15.0\cimex application\cimcad\macro directory.cpp(166) : see reference to function template instantiation 'bool contains<CString,substring_container_adapter,CMacroInterpreter::GetDirectoryOf::<lambda_60eac39ee69a5bdc77e08d06d79ae4c4>>(const COLLECTION &,ELEMENT,PREDICATE)' being compiled 
1>   with 
1>   [ 
1>    COLLECTION=substring_container_adapter, 
1>    ELEMENT=CString, 
1>    PREDICATE=CMacroInterpreter::GetDirectoryOf::<lambda_60eac39ee69a5bdc77e08d06d79ae4c4> 
1>   ] 

我如何強制事情接受謂詞拉姆達不清楚。似乎boost不能推斷lambda的返回類型。我不清楚我能做些什麼來解決這個問題?

我可以定義一個本地std :: binary_function派生函子。看起來好像修復包含<>來允許它直接處理lambdas。

+0

我想我們大家都同意,_all uppercase_其中預留_macros _... –

+1

呃名...所以是不是一個有效的模板標識?大聲笑 – Mordachai

+1

......你只是打斷我的意見,先生。也就是說,我們看到模擬代碼在真實世界中爆發出來,因爲一些虛擬物理庫決定聲明像'T'這樣的宏... –

回答

5

這似乎是boost::bind的問題。使用std::bind相反,你的代碼編譯罰款與VS2012 lambda表達式:

#include <functional> 
#include <algorithm> 
#include <vector> 

template <typename ELEMENT, typename COLLECTION, typename PREDICATE> 
bool contains(const COLLECTION & collection, ELEMENT element, PREDICATE predicate) 
{ 
    return collection.end() != std::find_if(collection.begin(), collection.end(), std::bind(predicate, element, std::placeholders::_1)); 
} 

std::vector<int> a; 

int main() 
{ 
    a.push_back(1); 
    a.push_back(2); 
    a.push_back(3); 
    a.push_back(42); 
    bool c = contains(a, 42, [](int a, int b) { return a == b; }); 
    return 0; 
} 

相同的代碼生成只是g++細爲好。

+0

爲了使用這段代碼,我必須包含哪些boost頭文件? – 0x499602D2

+0

我發佈的代碼不需要提升。 'std :: bind'與C++ 11標準中的'boost :: bind'基本相同。它可以通過包含「功能」頭部來使用。 –

2

你總是可以嘗試使用另一個lambda:

template <typename ELEMENT, typename COLLECTION, typename PREDICATE> 
bool contains(const COLLECTION & collection, ELEMENT element, PREDICATE predicate) 
{ 
    typedef typename COLLECTION::value_type VALUE; 

    return collection.end() != std::find_if(collection.begin(), collection.end(), 
     [&](VALUE const & e){ return predicate(element, e); }); 
} 
+0

'_1'發生了什麼? – 0x499602D2

+0

有趣的想法。謝謝。 – Mordachai

+0

@David'_1'表示由'bind'生成的對象的函數操作符上的第一個參數。在'std :: find_if'的情況下,這是來自被評估容器的元素。因此'bind(predicate,element,_1)'產生一個一元函數對象,它相當於調用'predicate(element,_1)'。我的答案中的lambda表達式執行相同的操作,不需要任何庫。 –