Domanda

Ho la seguente macro:

#define FOREACH(decl, c) BOOST_FOREACH(decl, std::make_pair((c).begin(), (c).end()))

(Sto usando questa macro, perché i miei contenitori non implementano l'API di iterazione mutabile.)

Il problema con esso è quello c viene valutato due volte.

La mia domanda è che questa macro può essere risolta in modo che:

  1. c viene valutato al massimo una volta
  2. Eventuali variabili locali create per soddisfare la prima condizione vivono solo all'interno del rispettivo portata di forea.
È stato utile?

Soluzione

È possibile utilizzare una funzione di supporto in linea.

#define FOREACH(decl, c) BOOST_FOREACH(decl, pair_helper(c))

template <typename T>
inline std::pair<typename T::iterator, typename T::iterator> pair_helper (T c) {
    return std::make_pair(c.begin(), c.end());
}

Altri suggerimenti

Non è necessario questo hackery. Boost.foreach si basa su boost.Range per recuperare gli iteratori. Che ci sono due modi per estenderlo:

  1. Fornire funzioni dei membri e un tipo nidificato: http://www.boost.org/doc/libs/1_48_0/libs/range/doc/html/range/rence/extending/method_1.html
  2. Fornire funzioni indipendenti e specializzare i metafunzioni: http://www.boost.org/doc/libs/1_48_0/libs/range/doc/html/range/rence/extending/method_2.html

Ora nel tuo caso, sembra che tu fornisca il begin() e end() funzioni del membro, ma non fornire il tipo nidificato iterator(Suppongo che sia quello che intendi per l'API di iterazione mutabile). Puoi fare una delle due cose.

Innanzitutto, puoi typedef Il tipo di iteratore nidificato come questo:

typedef const_iterator iterator;

In secondo luogo, se non puoi modificare la classe, puoi specializzare i metafunzioni, in questo modo (sostituendo il tuo contesto con qualunque sia il tipo di contenitore):

namespace boost
{
    //
    // Specialize metafunctions. We must include the range.hpp header.
    // We must open the 'boost' namespace.
    //

    template< >
    struct range_mutable_iterator< YourContainer >
    {
        typedef YourContainer::const_iterator type;
    };

    template< >
    struct range_const_iterator< YourContainer >
    {
        typedef YourContainer::const_iterator type;
    };

} // namespace 'boost'

Ovviamente presumo che tu abbia un const_iterator typedef'D nella tua classe (da quando hai detto che non supporta mutabile). Se non lo fai, dovrai sostituire YourContainer::const_iterator con qualunque tipo di tuo tipo const_iterator è.

Le "espressioni di istruzione" sono a estensione GCC/G ++ per evitare la ripetuta valutazione degli argomenti macro

#define make_pair_of_iterators(c) ({typeof(c)& c_ = (c); make_pair(c_.begin(), c_.end()); })

Allora potresti fare:

#define FOREACH(decl, c) BOOST_FOREACH(decl, make_pair_of_iterators(c) )

(E typeof è anche un'estensione GCC/G ++.)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top