dariomt@gmail.com wrote:
Tobias Schwinger wrote:
Here's an MPL-based solution.
Whoa! Thanks a lot!
compiles with GCC4
For me it also works with VS2003
Good.
Right now I'm still scratching my head in astonishment ;)
I'll definitely come back looking for some more help to understand your
solution.
The algorithm is quite easy -- the details around it take some time to
get used to :). Here's a runtime version of the metaprogram simulating
types with strings.
Regards,
Tobias
#include <vector>
#include
#include <string>
#include <iostream>
typedef std::string type;
typedef std::vector<type> type_vector;
class cursor
{
type_vector::const_iterator here, start, end;
public:
cursor(type_vector const& l)
: here(l.begin()), start(l.begin()), end(l.end())
{ }
// A return value of true means: "We reached the end and reset the position
// to the start" ('wrapped' member in compile time version).
//
// Note: We change the state of the cursor, here.
// Compile time algorithms are strictly functional, so the 'next' and
// 'wrap_around' metafunctions have to create new cursor types.
bool wrapping_next()
{
if (++here == end)
{
here = start;
return true;
}
return false;
}
type deref() const
{
return *here;
}
};
typedef std::vector<cursor> cursor_vector;
// Returns 'true' if all combinations (if any) have been processed.
bool nested_loops_step(cursor_vector& cursors)
{
// Note: In compile time world we create a new sequence since types are
// immutable -- once they are there we can't change them.
for (cursor_vector::iterator i = cursors.begin(), e = cursors.end();
i != e; ++i)
if (! i->wrapping_next())
return false;
return true;
}
int main()
{
using namespace boost::assign;
type_vector l1; l1 += std::string("A1"), std::string("A2");
type_vector l2; l2 += std::string("B1"), std::string("B2");
type_vector l3; l3 += std::string("C1"), std::string("C2");
cursor_vector cursors; cursors += cursor(l1), cursor(l2), cursor(l3);
// Note: We use the algorithm to determine whether there is something
// to do in the first place (just like the compile time version).
// However, the runtime version works directly on mutable cursors, so
// we copy the sequence to ignore its effect on the cursors.
cursor_vector disposable_copy_of_cursors(cursors);
if (! nested_loops_step(disposable_copy_of_cursors))
{
do
{
std::cout << cursors[0].deref() << ',' << cursors[1].deref() << ','
<< cursors[2].deref() << std::endl;
} while (! nested_loops_step(cursors));
}
}