Skip to content

Instantly share code, notes, and snippets.

@splinterofchaos
Created December 1, 2012 14:24
Show Gist options
  • Save splinterofchaos/4182570 to your computer and use it in GitHub Desktop.
Save splinterofchaos/4182570 to your computer and use it in GitHub Desktop.
To move a lambda.
#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