2012-05-31 31 views
2

考慮下面的代碼使用BOOST_FOREACH宏遍歷侵入名單:使用BOOST_FOREACH以恆定的侵擾列表

#include <boost/foreach.hpp> 
#include <boost/intrusive/list.hpp> 

typedef boost::intrusive::list< 
    boost::intrusive::list_base_hook<> > MyList; 

void iterate (const MyList& xs) { 
    BOOST_FOREACH (MyList::const_reference node, xs); 
} 

int main() { 
    MyList xs; 
    iterate (xs); 
    return 0; 
} 

鑑於提升1.48版的代碼失敗,鐺3.2(SVN)和gcc 4.6.3 ,但使用gcc 4.5.3。使用非const限定參數xsiterate該代碼有效。隨着C++ 11的啓用,所有的編譯器都接受這些代碼。當使用boost-1.46時,兩個gcc版本都接受這個代碼,但是clang仍然沒有。

手頭的代碼是否濫用了BOOST_FOREACH宏,或者是助手端的錯誤?有沒有比常規for循環更好的解決方法?

編輯: 我粘貼錯誤消息引擎收錄(兩者都是非常詳細)爲GCCclang

+0

還是接受提升不支持clang? –

+0

不可接受。它仍然會失敗,gcc-4.6.3,我最終會編寫常規for循環。 –

+1

如果我們實際上可以看到兩個編譯器的錯誤消息,那將很酷。 –

回答

2

這裏我可以從日誌中收集什麼,以及我對於失敗原因的推論。

簡版:出於某種原因BOOST_FOREACH試圖複製不可能的數據。

還有就是Extensibility頁面上的提示:

使BOOST_FOREACH工作具有不可複製的序列類型

對於那些不可複製的序列類型,我們需要告訴BOOST_FOREACH到不要嘗試複製。如果我們的類型繼承自boost::noncopyable,則不需要採取進一步的操作。否則,我們必須專門化boost::foreach::is_noncopyable<>模板[...]另一種達到同樣效果的方法是覆蓋全局函數boost_foreach_is_noncopyable()。這樣做的好處是可以移植到較老的編譯器。

從診斷結果來看,目前還不清楚類型是否配置正確,因此您可能需要一試。


剪枝診斷和分析。

/usr/include/boost/foreach.hpp:571:37: error: no matching constructor for initialization of 'boost::intrusive::list< >' 
     ::new(this->data.address()) T(t); 
            ^~ 
/usr/include/boost/foreach.hpp:648:51: note: in instantiation of member function 'boost::foreach_detail_::simple_variant<boost::intrusive::list< > >::simple_variant' requested here 
    return auto_any<simple_variant<T> >(*rvalue ? simple_variant<T>(t) : simple_variant<T>(&t)); 
               ^

/usr/include/boost/intrusive/list.hpp:1490:35: note: candidate constructor not viable: 1st argument ('const boost::intrusive::list< >') would lose const qualifier 
    BOOST_MOVABLE_BUT_NOT_COPYABLE(list) 
           ^
/usr/include/boost/move/move.hpp:371:7: note: expanded from macro 'BOOST_MOVABLE_BUT_NOT_COPYABLE' 
     TYPE(TYPE &);\ 

/usr/include/boost/intrusive/list.hpp:1497:4: note: candidate constructor not viable: no known conversion from 'const boost::intrusive::list< >' to 'const value_traits' (aka 'const boost::intrusive::detail::base_hook_traits<boost::intrusive::list_base_hook< >, boost::intrusive::list_node_traits<void *>, 1, boost::intrusive::default_tag, 1>') for 1st argument; 
    list(const value_traits &v_traits = value_traits()) 
^
/usr/include/boost/intrusive/list.hpp:1506:4: note: candidate constructor not viable: no known conversion from 'const boost::intrusive::list< >' to '::boost::rv<list< >> &' for 1st argument; 
    list(BOOST_RV_REF(list) x) 
^
/usr/include/boost/intrusive/list.hpp:1502:4: note: candidate constructor template not viable: requires at least 2 arguments, but 1 was provided 
    list(Iterator b, Iterator e, const value_traits &v_traits = value_traits()) 
^

我試圖找出錯誤儘可能地(除去回溯等。)顯然,這個問題從boost::intrusive::list莖,更確切地說是無法從boost::intrusive::list<> const建立一個新的boost::intrusive::list<>

最有前途的構造是由一個宏定義:

BOOST_MOVABLE_BUT_NOT_COPYABLE(list) 

它擴展到

list(list&); 

這是提升的方式模擬移動爲不可複製的類型在C++ 03的語義。但由於const限定符將丟失,因此它不能從const項目移動。

這似乎是BOOST_FOREACH爲避免對容器參數的多重評估(如果它是一個函數調用)所使用的詭計的一部分,儘管我有點驚訝它試圖在這裏複製參數。

+0

謝謝!正是我在找什麼。 –

0

既然你正在使用gcc> 4.6和鐺3.2,你可以使用C++ 11的射程爲基礎的looops:

#include <boost/foreach.hpp> 
#include <boost/intrusive/list.hpp> 

typedef boost::intrusive::list< 
    boost::intrusive::list_base_hook<> > MyList; 

void iterate (const MyList& xs) { 
    for(const auto &node : xs) { 
     // do something with node 
    } 
} 

int main() { 
    MyList xs; 
    iterate (xs); 
    return 0; 
} 

您還可以使用std::for_each

void iterate (const MyList& xs) { 
    std::for_each(xs.begin(), xs.end(), 
     [](MyList::const_reference node) { 
     // do something with node 
     } 
    ); 
} 
+0

很棒的建議,但不幸的是需要保持C++ 03的兼容性。 –