Skip to content

Instantly share code, notes, and snippets.

@loliGothicK
Created November 7, 2016 07:26
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save loliGothicK/c85b04c80063875e9492353759fe71f6 to your computer and use it in GitHub Desktop.
Save loliGothicK/c85b04c80063875e9492353759fe71f6 to your computer and use it in GitHub Desktop.
可変長引数を関数オブジェクトにバインドして後から指定した関数に渡す感じのやーつ
#include <iostream>
#include <functional>
#include <vector>
#include <initializer_list>
#include <utility>
#include <tuple>
#include <memory>
namespace cranberries {
template < typename F, typename Tuple, size_t... I >
decltype(auto) apply_impl( F&& f, Tuple&& t, std::index_sequence<I...> ) {
return f( std::forward<decltype(std::get<I>( t ))>( std::get<I>( t ) )... );
}
template < typename F, typename... Args >
decltype(auto) apply( F&& f, std::tuple<Args...> const& t ) {
return apply_impl( std::forward<F>( f ), t, std::index_sequence_for<Args...>{} );
}
}
class hoge {
public:
hoge() = default;
~hoge() = default;
hoge( hoge const& x ) : ptr{ std::make_unique<int>( *x.ptr ) } {
std::cout << "copy constructed" << std::endl;
}
hoge( hoge&& x ) : ptr{ std::move( x.ptr ) } {
std::cout << "move constructed" << std::endl;
}
hoge( int a ) : ptr{ std::make_unique<int>( a ) } {}
hoge& operator=( hoge const& x ) {
std::cout << "copy assigned" << std::endl;
*ptr = *x.ptr;
return *this;
}
hoge& operator=( hoge&& x ) {
std::cout << "move assigned" << std::endl;
ptr = std::move( x.ptr );
return *this;
}
auto* get() const {
return ptr.get();
}
decltype(auto) print( std::ostream& os ) const {
return os << *ptr;
}
private:
std::unique_ptr<int> ptr{};
};
decltype(auto) operator<< ( std::ostream& os, hoge const& x ) {
return x.print( os );
}
int main() {
// バインドする変数
hoge x{ 1 };
std::cout << "#1 : " << x.get() << std::endl;
/*
ラムダ式バージョン
*/
// #1 可変長引数をとる関数がラムダ式を返す
// #2 ラムダ式に可変長引数をバインドする
// #3 可変長引数を初期化キャプチャできないのでtupleに固めて初期化キャプチャ
// #4 ラムダ式が実行され、関数が指定されるとtupleを展開して関数に渡す
auto lambda = []( auto&&... args ) {
// #1
return [/* #2,#3 */t = std::make_tuple( std::move( args )... )]( auto&& func, auto&& ... ){
return cranberries::apply( func, t ); // #4
};
}(x);
// 呼び出し
lambda([]( auto&& head, auto&& ... ) {
std::cout << "#2 : " << head.get() << std::endl;
});
// バインドする変数
hoge y{ 2 };
std::cout << "#3 : " << y.get() << std::endl;
/*
std::bindバージョン
*/
// #1 可変長式数をとる関数がバインドオブジェクトを返す
// #2 bindに束縛させる関数はあとで指定する関数とその引数の両方を引数に取る関数(今回はラムダ式で書いた)
// #3 後で関数を指定するために第1引数はプレースホルダ
// #4 可変長引数をムーブしてバインドオブジェクトに束縛する
auto&& bind_expr = []( auto&& ...args ) {
// #1
return std::bind(
/* #2 */[]( auto&& func, auto&& ...args ) { return func( std::forward<decltype(args)>( args )... ); },
std::placeholders::_1, // #3
std::move( args )... ); // #4
}(y);
// 呼び出し
bind_expr(
[]( auto&& head, auto&& ... ) {
std::cout << "#4 : " << head.get() << std::endl;
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment