BOOST_FOREACH неявное использование ссылки? - PullRequest
3 голосов
/ 02 марта 2010

Мне интересно, есть ли какая-то польза от получения ссылки на вектор до вызова BOOST_FOREACH или будет ли автоматически использоваться вызов метода, который возвращает ссылку? Например, какой из двух следующих циклов будет эквивалентен третьему циклу?

vector<float>& my_method();

void main()
{
    // LOOP 1 -------------------------------
    vector<float>& temp_vector = my_method();
    BOOST_FOREACH(float element, temp_vector)
        cout << element << endl;

    // LOOP 2 -------------------------------
    vector<float> temp_vector = my_method();
    BOOST_FOREACH(float element, temp_vector)
        cout << element << endl;

    // Which loop is this one most like? ----
    BOOST_FOREACH(float element, my_method())
        cout << element << endl;
}

Ответы [ 3 ]

4 голосов
/ 02 марта 2010

Быстрый тест показывает, что функция вызывается один раз, и в связи с BOOST_FOREACH.

копирование не выполняется.
#include <vector>
#include <iostream>
#include <boost/foreach.hpp>

struct X
{
    X() {}
    X(const X& ) { std::cout << "copied\n"; }
};

std::vector<X> vec(2);

//std::vector<X> method()
std::vector<X>& method()
{
    std::cout << "returning from method\n";
    return vec;
}

int main()
{
    BOOST_FOREACH(const X& x, method()) {}
}
2 голосов
/ 02 марта 2010

Просматривая BOOST_FOREACH безумие метапрограммирования, я вижу, что коллекция копируется, если она

  1. значение,
  2. «облегченный прокси», который вы можете определить для своих типов по специализации boost::foreach::is_lightweight_proxy.

Следовательно, lvalue не копируется . Вместо этого его указатель считается временным.

Важный бит это:

# define BOOST_FOREACH_SHOULD_COPY(COL)             \
     (true ? 0 : boost::foreach_detail_::or_(       \
         BOOST_FOREACH_IS_RVALUE(COL)               \
       , BOOST_FOREACH_IS_LIGHTWEIGHT_PROXY(COL)))

Затем он используется в качестве одного из аргументов функции, которая используется для вычисления контейнера во временную переменную:

template<typename T> 
inline auto_any<T> contain(T const &t, boost::mpl::true_ *) // rvalue 
{ 
    return t;
}

template<typename T>
inline auto_any<T *> contain(T &t, boost::mpl::false_ *) // lvalue
{
    // Cannot seem to get sunpro to handle addressof() with array types.
    #if BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x570))
    return &t;
    #else
    return boost::addressof(t);
    #endif
}

В моей системе установлен Boost v1.38.

0 голосов
/ 02 марта 2010

И хотя BOOST_FOREACH является макросом, он замечательно хорошо себя ведет. Он оценивает свои аргументы ровно один раз, что не приводит к неприятным сюрпризам

так что my_method() не будет вызываться более одного раза

Ссылки ведут себя как «нормальные» переменные с точки зрения пользователя, вы можете обращаться со ссылкой точно так, как если бы она была исходной переменной. Это не имеет значения для цикла foreach.

То есть оба цикла эквивалентны.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...