Created
June 24, 2012 10:02
-
-
Save MatthewSteel/2982696 to your computer and use it in GitHub Desktop.
A "proper" for-each algorithm for tuples in C++11. Everything type-checked, no virtual function calls, heterogeneous data works.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <tuple> | |
#include <iostream> | |
#include <stdexcept> | |
using namespace std; | |
/* | |
* "A partially specialized non-type argument expression shall not involve a | |
* template parameter of the partial specialization except when the argument | |
* expression is a simple identifier." | |
* A hack to wrap our ints so we can do partial specialisation for the | |
* end-iterator class. | |
*/ | |
template<int n> struct IntType { | |
public: | |
const static int get=n; | |
}; | |
/* | |
* Iterator class. Everything type-checked properly, no inheritance or any of | |
* that garbage. | |
* Have written assignment and equality operators, a plus<int>() func, not | |
* included for brevity. | |
*/ | |
template<typename Tuple, typename n=IntType<0>> | |
class TupleIterator { | |
public: | |
TupleIterator(Tuple &t) : t(t) {} | |
typename tuple_element<n::get, Tuple>::type& operator*() { | |
return get<n::get>(t); | |
} | |
TupleIterator<Tuple, IntType<n::get+1>> operator++() { | |
return TupleIterator<Tuple, IntType<n::get+1>>(t); | |
} | |
private: | |
Tuple &t; | |
}; | |
/*partial specialisation for an `end` pointer. Could give it a deref method | |
that throws if we wanted nice runtime errors instead of ugly compile-time | |
ones... */ | |
template<typename Tuple> | |
class TupleIterator<Tuple, IntType<tuple_size<Tuple>::value>> { | |
public: | |
TupleIterator(Tuple &t) : t(t) {} | |
private: | |
Tuple &t; | |
}; | |
/* | |
* begin/end for algorithms. | |
*/ | |
template<typename Tuple> | |
TupleIterator<Tuple, IntType<0>> begin(Tuple &t) { | |
return TupleIterator<Tuple>(t); | |
} | |
template<typename Tuple> | |
TupleIterator<Tuple, IntType<tuple_size<Tuple>::value>> end(Tuple &t) { | |
return TupleIterator<Tuple, IntType<tuple_size<Tuple>::value>>(t); | |
} | |
/* | |
* for-each algorithm. Kinda "recursive", but never uses same template | |
* instantiation in a loop. GCC seems to get confused after about depth=3 and | |
* starts generating crappier code... | |
*/ | |
template<template<typename> class Func, typename Iterator, typename End> | |
void tuple_for_each(Iterator i, End e) { | |
Func<decltype(*i)> f; | |
f(*i); | |
tuple_for_each<Func>(++i, e);//recursive call | |
} | |
//Base case: i==e, so do nothing | |
template<template<typename> class Func, typename End> | |
void tuple_for_each(End i, End e) {} | |
/* | |
* The templated function object we pass to the for-each. Tried to use a | |
* regular templated function, but I'm not sure that's allowed. Wrapping it up | |
* doesn't cost anything. | |
* Unfortunately, lambdas in C++11 aren't polymorphic, so we're stuck in 1998 | |
* writing this stuff away from where we use it unless we use macros. | |
* Also: This is more powerful than it looks, because we can write template- | |
* specialisations for whatever classes we like. Super duper. | |
*/ | |
template<typename T> | |
struct println { | |
void operator()(T& t) { | |
cout << t << endl; | |
} | |
}; | |
int main() | |
{ | |
auto t = make_tuple(1, 2.1, "three"); | |
tuple_for_each<println>(begin(t), end(t)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment