♻️
C++11 で C++20 の bind_front 使えるようにする
以下のヘッダをインクルードすれば使えるようになるはず
※ g++4.9 で確認
bind_front.hpp
#pragma once
#include <functional>
#ifndef __cpp_lib_bind_front
namespace std {
// N は bind 後の残りの引数の数
// I は再帰用 (std::placeholders::_n の数)
template <size_t N, size_t I = 0>
struct BindFront
{
template <typename ...T>
static auto bind(T &&...args)
-> decltype(BindFront<N, I + 1>::bind(std::forward<T>(args)..., std::_Placeholder<I + 1>{}))
{
// gcc は std::_Placeholder<n>{} で std::placeholders::_n が取れる
// clang の場合は std::placeholders::__ph<n>{} で取れる
// VC++ は std::_Ph<n>{}
// 再帰で std::placeholders::_n を増やしていく
return BindFront<N, I + 1>::bind(std::forward<T>(args)..., std::_Placeholder<I + 1>{});
}
};
// 特殊化で N == I の時 std::bind に投げる
template <size_t N>
struct BindFront<N, N>
{
template <typename ...T>
static auto bind(T &&...args)
-> decltype(std::bind(std::forward<T>(args)...))
{
return std::bind(std::forward<T>(args)...);
}
};
// 以下 bind_front の定義
// const なメンバ関数用
template <typename TClass, typename TRet, typename ...TArgs, typename ...TObj>
auto bind_front(TRet(TClass::*func)(TArgs...) const, TObj &&...obj)
-> decltype(BindFront<sizeof...(TArgs) - sizeof...(TObj) + 1>::bind(func, std::forward<TObj>(obj)...))
{
return BindFront<sizeof...(TArgs) - sizeof...(TObj) + 1>::bind(func, std::forward<TObj>(obj)...);
}
// メンバ関数用
template <typename TClass, typename TRet, typename ...TArgs, typename ...TObj>
auto bind_front(TRet(TClass::*func)(TArgs...), TObj &&...obj)
-> decltype(BindFront<sizeof...(TArgs) - sizeof...(TObj) + 1>::bind(func, std::forward<TObj>(obj)...))
{
return BindFront<sizeof...(TArgs) - sizeof...(TObj) + 1>::bind(func, std::forward<TObj>(obj)...);
}
// 関数ポインタ用
template <typename TRet, typename ...TArgs, typename ...TObj>
auto bind_front(TRet(*func)(TArgs...), TObj &&...obj)
-> decltype(BindFront<sizeof...(TArgs) - sizeof...(TObj)>::bind(func, std::forward<TObj>(obj)...))
{
return BindFront<sizeof...(TArgs) - sizeof...(TObj)>::bind(func, std::forward<TObj>(obj)...);
}
// std::function 用
template <typename TRet, typename ...TArgs, typename ...TObj>
auto bind_front(const std::function<TRet(TArgs...)> &func, TObj &&...obj)
-> decltype(BindFront<sizeof...(TArgs) - sizeof...(TObj)>::bind(func, std::forward<TObj>(obj)...))
{
return BindFront<sizeof...(TArgs) - sizeof...(TObj)>::bind(func, std::forward<TObj>(obj)...);
}
// std::function&& 用
template <typename TRet, typename ...TArgs, typename ...TObj>
auto bind_front(std::function<TRet(TArgs...)> &&func, TObj &&...obj)
-> decltype(BindFront<sizeof...(TArgs) - sizeof...(TObj)>::bind(std::move(func), std::forward<TObj>(obj)...))
{
return BindFront<sizeof...(TArgs) - sizeof...(TObj)>::bind(std::move(func), std::forward<TObj>(obj)...);
}
} // std
#endif // __cpp_lib_bind_front
いちいち戻り値用の decltype に同じの書かなあかんのめんどくさい
ちなみにC++14だとこうなる
はやくC++17あたりになりたい
Discussion