No tengo experiencia concreta con LINQ, pero la biblioteca Boost.Iterator parece acercarse a lo que usted se refiere.
La idea es tener funciones (IIUC, en LINQ, toman la forma de métodos de extensión, pero eso no es fundamental), tomando un iterador y una función, combinándolos para crear un nuevo iterador.
LINQ "Donde" mapas a make_filter_iterator
:
std::vector<int> vec = ...;
// An iterator skipping values less than "2":
boost::make_filter_iterator(_1 > 2, vec.begin())
LINQ "Select" mapas a 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())
y pueden estar compuestos:
//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())
)
Sin embargo, hay son algunas cosas molestas con esto:
- El tipo devuelto por
make_xxx_iterator(some_functor, some_other_iterator)
es xxx_iterator<type_of_some_functor, type_of_some_iterator>
- El tipo de un funtor creado usando boost :: bind, lambda, o Fénix se convierte rápidamente en inmanejable grande e incómodo para escribir.
Es por eso que evité en el código anterior asignar el resultado de make_xxx_iterator
a una variable. La característica "auto" de C++ 0x será muy bienvenida allí.
Pero aún así, un iterador de C++ no puede vivir "solo": tienen que venir en pares para ser útiles.Por lo tanto, incluso con "auto", sigue siendo un bocado:
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())
);
Evitar el uso de lambda hace cosas prolijo, pero manejable:
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())
);
El (aún no) es la biblioteca Boost.RangeEx prometedor a este respecto, ya que permite combinar los dos iteradores en un solo rango. Algo así como:
auto filtered_and_transformed = make_transform_range(
make_filter_range(vec, _1 > 2),
construct<std::string>('*', _1)
);
Posible duplicado: http://stackoverflow.com/questions/232222/is-there-a-linq-library-for-c --¡entonces vez más que pueden diferir he dudado de si esto es realmente un " exacto 'duplicado –
No estoy interesado específicamente en LINQ, sino en el procesamiento de listas de estilo funcional en C++. –
Específicamente, los lambda son agradables, pero no cruciales. –