2012-03-22 58 views
4

傳統的任務迭代谷鍵集std::map導致我另一個混亂,似乎還沒有在這裏討論。boost :: transform_iterator不適用於std :: bind(&Pair :: first,_1)?

總之,這代碼不編譯(C++ 11被大量使用):

typedef std::pair<int, int> Pair; 
vector<Pair> v {Pair(1,2), Pair(2,3)}; 
using namespace std::placeholders; 
auto choose_first = std::bind(&Pair::first, _1); 
boost::make_transform_iterator(v.begin(), choose_first); 

錯誤消息如下。

no type named 'result_type' in 'struct std::_Bind<std::_Mem_fn<int std::pair<int, int>::*>(std::_Placeholder<1>)>' 

同時,改變std::bindboost::bind解決問題。但是我的項目中有一個代碼約定,我們只使用std::bind

有什麼建議該怎麼做? (我應該向Boost團隊寫錯誤報告嗎?)

回答

4

有更好的方法來遍歷在std::map的鍵(或者其value_typepair<T,U>任何容器),即Boost.Rangemap_keys適配器(也有一個map_values一個):

#include <boost/range/adaptor/map.hpp> 
#include <utility> 
#include <vector> 
#include <iostream> 

int main(){ 
    typedef std::pair<int, int> Pair; 
    std::vector<Pair> v {Pair(1,2), Pair(2,3)}; 
    for(auto& first : v | boost::adaptors::map_keys){ 
    std::cout << first << " "; 
    } 
} 

但是回到你的問題:所有Boost庫都使用Boost.Utility function result_of,它不會因爲任何原因回退到std::result_of,如果沒有告訴它可用,也不會使用decltype。通過在第一次包括Boost之前加入#define BOOST_RESULT_OF_USE_DECLTYPE來做到這一點。

然而,這仍然沒有讓你的代碼與鏗鏘3.1 SVN + libC++編譯。下面是我使用的代碼:

#define BOOST_RESULT_OF_USE_DECLTYPE 
#include <boost/iterator/transform_iterator.hpp> 
#include <utility> 
#include <vector> 
#include <functional> 

int main(){ 
    typedef std::pair<int, int> Pair; 
    std::vector<Pair> v {Pair(1,2), Pair(2,3)}; 
    using namespace std::placeholders; 
    auto choose_first = std::bind(&Pair::first, _1); 
    boost::make_transform_iterator(v.begin(), choose_first); 
} 

編譯時:

clang++ -std=c++0x -stdlib=libc++ -Wall -pedantic -Ipath/to/boost -Wno-mismatched-tags t.cpp 

GCC 4.7似乎接受了這個就好了,所以我想這是在libc中的錯誤++。

+0

至於map_keys:實際上在最後我使用了一些通用函數,它接受滿足STL容器要求(begin(),end())的對象。所以在創建轉換迭代器之後,我將它們打包到boost :: iterator_range中並將其提供給我的函數。我無法弄清楚,如何更快地做到這一點。 BOOST_RESULT_OF_USE_DECLTYPE在Boost 1.46,GCC 4.6.1中由於某些原因沒有幫助。也許我做錯了什麼...... – 2012-03-22 14:53:35

+0

@Artem:Boost.Range適配器返回的所有範圍都有'begin()'和'end()'成員,否則他們將無法使用range-for,如我所示。 :)所以只要做'your_generic_func(v | map_keys)'。 – Xeo 2012-03-22 14:59:18

+0

非常感謝! 'your_generic_func(v | map_keys)'工作正常! – 2012-03-22 15:10:37

1

看起來您需要在包含boost庫之前定義BOOST_RESULT_OF_USE_DECLTYPE,以便實際使用C++ 11方法獲取結果類型,而不是依賴於傳統的result_type成員。這將編譯的G ++ 4.6和4.8罰款:

#define BOOST_RESULT_OF_USE_DECLTYPE 
//^

#include <vector> 
#include <boost/iterator/transform_iterator.hpp> 
#include <functional> 

int main() 
{ 

typedef std::pair<int, int> Pair; 
std::vector<Pair> v {Pair(1,2), Pair(2,3)}; 
using namespace std::placeholders; 
auto choose_first = std::bind(&Pair::first, _1); 
boost::make_transform_iterator(v.begin(), choose_first); 

} 

見話題http://lists.boost.org/boost-users/2012/01/72856.php知道爲什麼它不是默認啓用的。


您也可以通過使用std::mem_fn代替std::bind解決辦法,

auto choose_first = std::mem_fn(&Pair::first); 

這確實定義這些傳統類型成員(§20.8.10/ 2)。由於std::mem_fn仍然是標準庫的一部分,我相信在團隊中使用它沒有問題...?


作爲最後的手段,你總是可以使用C++ 03的方式來聲明一個函數對象(當然,我們知道std::unary_function已經過時):

template <typename T> 
struct FirstChooser : 
     public std::unary_function<const T&, typename T::first_type> 
{ 
    typename T::first_type operator()(const T& input) const 
    { 
     return input.first; 
    } 
}; 

... 

FirstChooser<Pair> choose_first; 
+0

我也在標準中看到std :: mem_fn的這個要求,但是GCC 4.6.1仍然說:'struct std :: _ Mem_fn :: *>'中沒有​​類型命名爲'result_type'。至於BOOST_RESULT_OF_USE_DECLTYPE:對於Boost版本1.46,它不會改變任何內容。是否必須使用更新版本的Boost? – 2012-03-22 14:29:45

+0

@ArtemPelenitsyn是否在任何其他include_?之前定義了它? – sehe 2012-03-22 14:34:39

+0

@絕對。 – 2012-03-22 14:37:52