2

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;
}

Boostバージョン1.48を指定すると、コードはclang 3.2(SVN)およびgcc 4.6.3で失敗しますが、gcc4.5.3では機能します。コードxsへの非const修飾パラメーターを使用すると機能します。iterateC ++ 11を有効にすると、すべてのコンパイラがコードを受け入れます。boost-1.46を使用する場合、両方のgccバージョンがコードを受け入れますが、clangはまだ受け入れません。

手元のコードはマクロの誤用BOOST_FOREACHですか、それともブースト側のエラーですか?通常のforループでの反復よりも優れた回避策はありますか?

編集: GCCclangのエラーメッセージをpastebin(どちらも非常に冗長です)に貼り付けました。

4

2 に答える 2

2

これが私がログから集めることができたものと失敗の原因に関する私の推論です。

短いバージョン:何らかの理由BOOST_FOREACHでデータをコピーしようとしますが、これは不可能です。

拡張性ページにメモがあります:

コピー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<>から新しいものを構築できないことに起因しているようboost::intrusive::list<> constです。

最も有望なコンストラクターは、マクロによって定義されます。

BOOST_MOVABLE_BUT_NOT_COPYABLE(list)

これはに拡張されます

list(list&);

これは、boostがC++03のコピー不可能なタイプの移動セマンティクスをエミュレートする方法です。ただし、修飾子が失われるため、constアイテムから移動することはできません。const

これは、コンテナ引数の複数の評価を回避するために使用されるトリックの一部のように見えBOOST_FOREACHます(関数呼び出しの場合)が、ここで引数をコピーしようとしていることに少し驚いています。

于 2012-05-31T16:34:58.093 に答える
1

gcc>4.6およびclang3.2を使用しているため、ループにはC++11の範囲ベースを使用できます。

#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
      }
    );
}
于 2012-05-31T15:35:30.987 に答える