
LINQ to Objects in C ++
It all started with the fact that I was at the institute and after graduation I wrote code in C ++ and did not know the troubles. But then one day I had to write code for .NET in C #. At first, he spat a little, but then nothing - he got involved. I saw beneficial differences from C ++: security, rigor, etc. I also could not ignore LINQ when working with collections ...

But I appreciated all the charm of LINQ when it was time to return to C ++. It was a bit unusual to write in C ++ after a six-month break. Nothing boded ill, when suddenly I had to calculate the sum of the elements in the vector, more specifically the sum of the fields of the elements of the vector. In C #, this would be solved like this:
But in C ++ it came out:
And if you rewrite iterators:
Qt makes things a little easier, but not too much:
Also, the new C ++ 11 language standard promises us simplification,
but Visual Studio 2010alas does not support this feature , but how ... (thanks Damaskus ):
You quickly get used to the good. It was a complete mess. All of these options did not suit me. We needed a one-line solution. Then I began to google and found on the very first link: http://stackoverflow.com/questions/3221812/sum-of-elements-in-a-stdvector
The shortest of the proposed solutions:
But what to do if you need to add the values of only one of the fields. You can of course make a cunning iterator that, when dereferenced, returns one of the fields ... But it all smacks of hard coding for such a simple task.
The next 20-30 minutes of googling showed that there are Boost Ranges and a couple of other libraries, but they all looked different from what LINQ looks like. At that very moment, I felt the strength in myself - to write my implementation and cover it with tests.
The main tasks for me were:
This is how the boolinq project appeared (the name combines the words bool and linq ). Posted it on Google Code: http://code.google.com/p/boolinq/ . And here is what I got:
Of course, it looks a bit more complicated than LINQ. But, this is only due to the syntax of lambda expressions in C ++. The very structure of the code remains the same. Currently, the following functions are implemented:
Transformations of sequences:
Sequence Aggregators:
Export Sequence:
And even a few unusual ones:
Here is an example expression:
Several operations are applied step by step to the original collection:
1. Leave only elements with an odd value.
2. Multiply the value of each element by 2.
3. Leave only the elements with values in the range (2,12).
4. The result is placed in
Or a more complex expression:
The type of the variable
The result is a library of deferred queries to arrays, vectors, and other data containers. The speed of functions is not inferior to the speed of a similar program written using cycles. The syntax is as close as possible to LINQ. I enjoyed spending time designing and developing the functionality of the library. The code is well covered by tests (I don’t know how many percent, if someone tells me, I will be glad). There are functions that have no analogues in LINQ.
The library is distributed as a single header file

Introduction to the issue
But I appreciated all the charm of LINQ when it was time to return to C ++. It was a bit unusual to write in C ++ after a six-month break. Nothing boded ill, when suddenly I had to calculate the sum of the elements in the vector, more specifically the sum of the fields of the elements of the vector. In C #, this would be solved like this:
int sum = candles.Sum(c => c.ClosePrice);
But in C ++ it came out:
int sum = 0;
for(int i = 0; i < candles.size(); i++)
sum += candles[i].ClosePrice;
And if you rewrite iterators:
int sum = 0;
for(auto it = candles.begin(); it != candles.end(); ++it)
sum += it->ClosePrice;
Qt makes things a little easier, but not too much:
int sum = 0;
foreach(Candle candle, candles)
sum += candle.ClosePrice;
Also, the new C ++ 11 language standard promises us simplification,
but Visual Studio 2010
int sum = 0;
for (Candle candle : vector)
sum += candle.ClosePrice;
You quickly get used to the good. It was a complete mess. All of these options did not suit me. We needed a one-line solution. Then I began to google and found on the very first link: http://stackoverflow.com/questions/3221812/sum-of-elements-in-a-stdvector
The shortest of the proposed solutions:
int sum = std::accumulate(vector.begin(), vector.end(), 0);
But what to do if you need to add the values of only one of the fields. You can of course make a cunning iterator that, when dereferenced, returns one of the fields ... But it all smacks of hard coding for such a simple task.
What to do?
The next 20-30 minutes of googling showed that there are Boost Ranges and a couple of other libraries, but they all looked different from what LINQ looks like. At that very moment, I felt the strength in myself - to write my implementation and cover it with tests.
The main tasks for me were:
- Make the library as similar as possible to LINQ
- Make all the functionality “deferred” (lazy)
This is how the boolinq project appeared (the name combines the words bool and linq ). Posted it on Google Code: http://code.google.com/p/boolinq/ . And here is what I got:
int sum = boolinq::from(cnadles).sum([](Candle c){return c.ClosePrice;});
Of course, it looks a bit more complicated than LINQ. But, this is only due to the syntax of lambda expressions in C ++. The very structure of the code remains the same. Currently, the following functions are implemented:
Transformations of sequences:
- take (int)
- skip (int)
- concat (range)
- where (lambda)
- select (lambda)
- reverse ()
- orderBy ()
- orderBy (lambda)
- groupBy (lambda)
- distinct ()
- distinct (lambda)
- for_each (lambda)
Sequence Aggregators:
- all ()
- all (lambda)
- any ()
- any (lambda)
- sum ()
- sum (lambda)
- avg ()
- avg (lambda)
- min ()
- min (lambda)
- max ()
- max (lambda)
- count ()
- count (lambda)
- contains (value)
- elementAt (int)
Export Sequence:
- toSet ()
- toList ()
- toDeque ()
- toVector ()
- tocontainer
()
And even a few unusual ones:
- bytes ()
- bytes
() - unbytes
() - unbytes
() - bits ()
- bits
() - bits
() - unbits ()
- unbits
() - unbits
() - unbits
() - unbits
()
Usage example
Here is an example expression:
int src[] = {1,2,3,4,5,6,7,8};
auto dst = from(src).where( [](int a){return a%2 == 1;}) // 1,3,5,7
.select([](int a){return a*2;}) // 2,6,10,14
.where( [](int a){return a>2 && a<12;}) // 6,10
.toVector();
Several operations are applied step by step to the original collection:
1. Leave only elements with an odd value.
2. Multiply the value of each element by 2.
3. Leave only the elements with values in the range (2,12).
4. The result is placed in
std::vector
. Or a more complex expression:
struct Man
{
std::string name;
int age;
};
Man src[] =
{
{"Kevin",14},
{"Anton",18},
{"Agata",17},
{"Terra",20},
{"Layer",15},
};
auto dst = from(src).where( [](const Man & man){return man.age < 18;})
.orderBy([](const Man & man){return man.age;})
.select( [](const Man & man){return man.name;})
.toVector();
The type of the variable
dst
will be . The resulting vector will contain the following values: "Kevin", "Layer", "Agata". Actions applied to the original array:
1. Leave only people under the age of 18 in the array.
2. Arrange the elements in the array by increasing age.
3. Select only names from the array.
4. The result is placed in .std::vector
std::vector
Conclusion
The result is a library of deferred queries to arrays, vectors, and other data containers. The speed of functions is not inferior to the speed of a similar program written using cycles. The syntax is as close as possible to LINQ. I enjoyed spending time designing and developing the functionality of the library. The code is well covered by tests (I don’t know how many percent, if someone tells me, I will be glad). There are functions that have no analogues in LINQ.
The library is distributed as a single header file
boolinq-all.h
. I would be glad if someone finds the library useful. If there are suggestions for improvement, adding functions - please speak out. If you have time and desire to hang around - join. Everyone can leave comments on the code on Google Code. A discussion group has also been created on Google Groups: https://groups.google.com/forum/?fromgroups#!forum/boolinq