Reputation: 6449
I'd like to initialize std::set
with several ranges of numbers. I would like to do it efficiently (minimal copying), without using boost
and with good code readability for the end-user (myself :) at the moment).
Following is what I've come up with so far, but I can see a number of inefficiencies and wanted to get pointers on whether it is possible and how to fix them. Specific questions are below the code.
#include <iostream>
#include <set>
typedef std::set<int> codes;
template<typename T>
inline codes operator|(codes&& x, T&& y)
{
codes c(std::move(x));
c.insert(y.begin(), y.end());
return c;
}
template<typename T>
inline codes operator|(const codes& x, T&& y)
{
codes c(std::forward<T>(y));
c.insert(x.begin(), x.end());
return c;
}
inline codes range(int min, int max)
{
codes c;
for(int ri = min; ri < max; ++ri) c.insert(ri);
return c;
}
void print_set(const std::string& name, const codes& set)
{
std::cout << name << " = ";
for(int ri: set) std::cout << ri << ' ';
std::cout << std::endl;
}
int main()
{
codes r1 = { 1, 2, 3 };
codes r2 = range(5, 10);
codes r3 = r1 | r2;
codes r4 = r2 | range(15, 20);
codes r5 = range(1, 10) | r1;
codes r6 = range(1, 5) | range(10, 15);
print_set("r1", r1);
print_set("r2", r2);
print_set("r3", r3);
print_set("r4", r4);
print_set("r5", r5);
print_set("r6", r6);
return 0;
}
I wrote the operator|
as templates to deal with various combinations of r- and l-value references. However, the operator|(&& x, && y)
version still has to copy the elements from y
. Is it possible to avoid it?
The range
function executes at run-time. Is it possible to write a constexpr
version that runs at compile-time?
Anybody sees any other things that can be optimized?
Should I use an entirely different approach?
The key things are:
a) The code should be easily readable. In other words it should somewhat resemble the mathematical expression, eg: foo = [a, b) | [c, d)
b) The program will run on an embedded system, so code footprint and efficiency is important (hence, no boost
).
Upvotes: 0
Views: 3000
Reputation: 63775
All of this:
template<typename T>
inline codes operator|(codes&& x, T&& y)
{
codes c(std::move(x));
c.insert(y.begin(), y.end());
return c;
}
template<typename T>
inline codes operator|(const codes& x, T&& y)
{
codes c(std::forward<T>(y));
c.insert(x.begin(), x.end());
return c;
}
Could be written as:
template<typename T>
inline codes operator|(codes x, T&& y)
{
using std::begin;
using std::end;
x.insert( begin(y), end(y) );
return x;
}
Passing codes x
by value will implement the correct and already-well-tested std::set
constructors for both lvalues and rvalues.
Upvotes: 4