Skip to content

Instantly share code, notes, and snippets.

@NeuroWhAI
Last active May 28, 2017 03:30
Show Gist options
  • Save NeuroWhAI/01f14be9aeacffaffb7298c3677fd7d4 to your computer and use it in GitHub Desktop.
Save NeuroWhAI/01f14be9aeacffaffb7298c3677fd7d4 to your computer and use it in GitHub Desktop.
Parameters like Member variables
#include <memory>
#include <functional>
#include <type_traits>
#include <tuple>
#include <utility>
template <typename... ARGS>
class Action
{
private:
template <typename T>
using OrgT = std::remove_reference_t<T>;
public:
Action(std::function<void(ARGS...)> func)
: m_func(func)
, m_args(std::make_shared<OrgT<ARGS>>()...)
{
m_packed = pack(func);
}
Action(const Action& other)
: m_func(other.m_func)
, m_args(std::make_shared<OrgT<ARGS>>()...)
{
copyArguments(other.m_args);
m_packed = pack(other.m_func);
}
Action(Action&& other)
: m_func(std::move(other.m_func))
, m_args(std::move(other.m_args))
{
m_packed = pack(m_func);
}
private:
std::function<void(ARGS...)> m_func;
std::function<void()> m_packed;
std::tuple<std::shared_ptr<OrgT<ARGS>>...> m_args;
private:
void unpacker(std::function<void(ARGS...)> func, std::shared_ptr<OrgT<ARGS>>... args)
{
func(*args...);
}
template <std::size_t... I>
std::function<void()> packImpl(std::function<void(ARGS...)> func, std::index_sequence<I...>)
{
return std::bind(&Action::unpacker, this, func, std::get<I>(m_args)...);
}
std::function<void()> pack(std::function<void(ARGS...)> func)
{
return packImpl(func, std::index_sequence_for<ARGS...>{});
}
private:
template <std::size_t... I>
void copyArgumentsImpl(const std::tuple<std::shared_ptr<OrgT<ARGS>>...>& args, std::index_sequence<I...>)
{
using ExpandType = int[];
ExpandType{ 0, (*std::get<I>(m_args) = *std::get<I>(args), 0)... };
}
void copyArguments(const std::tuple<std::shared_ptr<OrgT<ARGS>>...>& args)
{
copyArgumentsImpl(args, std::index_sequence_for<ARGS...>{});
}
public:
void call()
{
m_packed();
}
void call(ARGS&&... args)
{
m_func(std::forward<ARGS>(args)...);
}
public:
void operator()()
{
call();
}
void operator()(ARGS&&... args)
{
call(std::forward<ARGS>(args)...);
}
public:
Action& operator=(const Action& other)
{
if (this == &other)
return *this;
m_func = other.m_func;
copyArguments(other.m_args);
m_packed = pack(other.m_func);
return *this;
}
Action& operator=(Action&& other)
{
if (this == &other)
return *this;
m_func = std::move(other.m_func);
m_args = std::move(other.m_args);
m_packed = pack(m_func);
return *this;
}
};
template <>
class Action<>
{
public:
Action(std::function<void()> func)
: m_func(func)
{ }
Action(const Action&) = default;
Action(Action&&) = default;
private:
std::function<void()> m_func;
public:
void call()
{
m_func();
}
public:
void operator()()
{
call();
}
public:
Action& operator=(const Action&) = default;
Action& operator=(Action&&) = default;
};
#include <iostream>
#include "Action.hpp"
using namespace std;
int main()
{
int foo = 0;
Action<int&> f1 = [](auto& data)
{
cout << ++data << endl;
};
// 포함 변수의 값이 잘 유지되는지 확인.
f1(); //> 1
f1(); //> 2
f1(); //> 3
// 직접 인수를 넣을 수 있는지 확인.
f1(foo); //> 1
f1(foo); //> 2
cout << "foo : " << foo << endl;
// 인수를 직접 넣으면 포함 변수 대신 들어가서 포함 변수에 영향을 안주는 것을 확인.
f1(); //> 4
// 복사 생성자 확인.
auto f2 = f1;
// 포함 변수의 값이 복사 되었는지 확인.
f2(); //> 5
f2(); //> 6
f2(); //> 7
// 함수와 포함 변수의 값은 복사되지만 포함 변수 자체는 각각 독립적으로 존재함을 확인.
f1(); //> 5
f1(); //> 6
// 대입 연산자 확인.
f1 = f2;
f1(); //> 8
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment