Created
December 1, 2012 14:24
-
-
Save splinterofchaos/4182570 to your computer and use it in GitHub Desktop.
To move a lambda.
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 <iostream> | |
#include <vector> | |
#include <algorithm> | |
using namespace std; | |
void print_vec( const char* const name, const vector<int>& v ) { | |
cout << name << " = "; | |
for( int x : v ) { | |
cout << x << " "; | |
} | |
cout << endl; | |
} | |
template< class F, class X > | |
struct Part { | |
F f; | |
X x; | |
template< class _F, class _X > | |
constexpr Part( _F&& f, _X&& x ) | |
: f(forward<_F>(f)), x(forward<_X>(x)) | |
{ | |
} | |
template< class ... Xs > | |
auto operator () ( Xs&& ...xs ) | |
-> decltype( f(x,declval<Xs>()...) ) | |
{ | |
return f( x, forward<Xs>(xs)... ); | |
} | |
}; | |
template< class F, class X > | |
constexpr Part<F,X> closet( F f, X x ) { | |
return Part<F,X>( std::move(f), std::move(x) ); | |
} | |
std::vector<int> add_all( std::vector<int>& v, int x ) { | |
// Arbitrarily move v. | |
auto w = std::move(v); | |
std::transform( w.begin(), w.end(), w.begin(), | |
closet(std::plus<int>(),x) ); | |
return w; | |
} | |
std::vector<int> add_all2( std::vector<int> w, int x ) { | |
std::transform( w.begin(), w.end(), w.begin(), | |
closet(std::plus<int>(),x) ); | |
return w; | |
} | |
// originate returns a partial application of add_all with a vector. | |
std::function<std::vector<int>()> bad_originate() { | |
std::vector<int> v = { 1, 2, 3, 4, 5 }; | |
// Move v, avoid upward funarg problem. | |
// en.wikipedia.org/wiki/Funarg_problem#Upwards_funarg_problem | |
return [&]{ return v; }; | |
} | |
// originate returns a partial application of add_all with a vector. | |
using Origin = Part<decltype(add_all)*,std::vector<int>>; | |
Origin originate() { | |
std::vector<int> v = { 1, 2, 3, 4, 5 }; | |
// Move v, avoid upward funarg problem. | |
// en.wikipedia.org/wiki/Funarg_problem#Upwards_funarg_problem | |
return closet( add_all, std::move(v) ); | |
} | |
template< class F, class G > struct Composition { | |
F f = F(); | |
G g = G(); | |
Composition() { } | |
Composition( F f, G g) | |
: f(move(f)), g(move(g)) { } | |
template< class X, class ...Y > | |
auto operator () ( X&& x, Y&& ...y ) | |
-> decltype( f(g(declval<X>()), declval<Y>()...) ) | |
{ | |
return f( g( forward<X>(x) ), forward<Y>(y)... ); | |
} | |
}; | |
template< class F, class G > | |
Composition<F,G> comp( F f, G g ) { | |
return Composition<F,G>( std::move(f), std::move(g) ); | |
} | |
constexpr struct Mover { | |
template< class X > | |
X&& operator () ( X& x ) const { | |
return std::move(x); | |
} | |
} mover{}; | |
using MoveAddAll = decltype( comp(add_all2,mover) ); | |
using Origin2 = Part< MoveAddAll, std::vector<int> >; | |
Origin2 originate2() { | |
std::vector<int> v = { 1, 2, 3, 4, 5 }; | |
// Move v, avoid upward funarg problem. | |
// en.wikipedia.org/wiki/Funarg_problem#Upwards_funarg_problem | |
return Origin2( comp(add_all2,mover), std::move(v) ); | |
} | |
int main() | |
{ | |
auto bad = bad_originate(); | |
print_vec( "bad : ", bad() ); | |
cout << "version 1:\n"; | |
Origin f = originate(); | |
print_vec( "original : ", f.x ); | |
print_vec( "added 10 : ", f(10) ); | |
print_vec( "original : ", f.x ); | |
cout << "\nversion 2:\n"; | |
Origin2 g = originate2(); | |
print_vec( "original : ", g.x ); | |
print_vec( "added 10 : ", g(10) ); | |
print_vec( "original : ", g.x ); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment