У меня нет конкретного опыта работы с LINQ, но библиотека Boost.Iterator, похоже, подходит к тому, о чем вы говорите.
Идея состоит в том, чтобы иметь функции (IIUC, в LINQ, они принимают форму методов расширения, но это не принципиально), принимая итератор и функцию, объединяя их для создания нового итератора.
LINQ "Где" карты для make_filter_iterator
:
std::vector<int> vec = ...;
// An iterator skipping values less than "2":
boost::make_filter_iterator(_1 > 2, vec.begin())
LINQ "Выбор" карты для make_transform_iterator
:
using namespace boost::lambda;
//An iterator over strings of length corresponding to the value
//of each element in "vec"
//For example, 2 yields "**", 3 "***" and so on.
boost::make_transform_iterator(construct<std::string>('*', _1), vec.begin())
И они могут быть составлены:
//An iterator over strings of length corresponding to the value of each element
// in "vec", excluding those less than 2
std::vector<int> vec = ...;
boost::make_transform_iterator(construct<std::string>('*', _1),
boost::make_filter_iterator(_1 > 2, vec.begin())
)
Тем не менее, есть несколько раздражающих вещей с этим:
- Тип возвращаемый
make_xxx_iterator(some_functor, some_other_iterator)
является xxx_iterator<type_of_some_functor, type_of_some_iterator>
- Тип функтора создан с использованием подталкивание :: привязывать, лямбда, или феникс быстро становится неуправляемо большим и громоздким писать.
Именно поэтому я избегал в приведенном выше коде, чтобы присвоить результат make_xxx_iterator
переменной. Функция C++ 0x «auto» будет очень приветствуемой.
Но все же Итератор C++ не может жить «в одиночку»: они должны попадать в пары, чтобы быть полезными.Таким образом, даже с "авто", это все еще глоток:
auto begin = make_transform_iterator(construct<std::string>('*', _1),
make_filter_iterator(_1 > 2, vec.begin())
);
auto end = make_transform_iterator(construct<std::string>('*', _1),
make_filter_iterator(_1 > 2, vec.end())
);
Отказ от использования лямбда делает вещи многословным, но управляемо:
struct MakeStringOf{
MakeStringOf(char C) : m_C(C){}
char m_C;
std::string operator()(int i){return std::string(m_C, i);}
};
struct IsGreaterThan{
IsGreaterThan(int I) : m_I(I){}
int m_I;
bool operator()(int i){return i > m_I;}
};
typedef boost::filter_iterator<
IsGreaterThan,
std::vector<int>::iterator
> filtered;
typedef boost::transform_iterator<
MakeStringOf,
filtered
> filtered_and_transformed;
filtered_and_transformed begin(
MakeStringOf('*'),
filtered(IsGreaterThan(2), vec.begin())
);
filtered_and_transformed end(
MakeStringOf('*'),
filtered(IsGreaterThan(2), vec.end())
);
The (не-пока) библиотека Boost.RangeEx является многообещающий в этом отношении, поскольку он позволяет объединить два итератора в одном диапазоне. Что-то вроде:
auto filtered_and_transformed = make_transform_range(
make_filter_range(vec, _1 > 2),
construct<std::string>('*', _1)
);
Возможный дубликат: http://stackoverflow.com/questions/232222/is-there-a-linq-library-for-c --then снова они могут отличаться, я сомневался, что это действительно " точный 'duplicate –
Я не интересуюсь LINQ специально, но в обработке списка функционального стиля на C++. –
В частности, лямбда хороша, но не имеет решающего значения. –