You can (partially) specialize std::is_placeholder
for specializations of a custom template. This way, you can introduce a placeholder generator via the usual int_sequence
technique.
From [func.bind.isplace]/2
The implementation shall provide a definition that has the BaseCharacteristic
of integral_constant<int, J>
if T
is the type of std::placeholders::_J
, otherwise it shall have a BaseCharacteristic
of integral_constant<int, 0>
. A program may specialize this template for a user-defined type T
to have a BaseCharacteristic
of integral_constant<int, N>
with N > 0
to indicate that T
should be treated as a placeholder type.
The usual int_sequence
:
#include <cstddef>
template<int...> struct int_sequence {};
template<int N, int... Is> struct make_int_sequence
: make_int_sequence<N-1, N-1, Is...> {};
template<int... Is> struct make_int_sequence<0, Is...>
: int_sequence<Is...> {};
The custom placeholder template and specialization of is_placeholder
:
template<int> // begin with 0 here!
struct placeholder_template
{};
#include <functional>
#include <type_traits>
namespace std
{
template<int N>
struct is_placeholder< placeholder_template<N> >
: integral_constant<int, N+1> // the one is important
{};
}
I'm not sure where to introduce the 1
; the places I considered are all not optimal.
Using it to write some binder:
template<class Ret, class... Args, int... Is>
void my_bind(Ret (*p)(Args...), int_sequence<Is...>)
{
auto x = std::bind(p, placeholder_template<Is>{}...);
x( Args(42)... );
}
template<class Ret, class... Args>
void my_bind(Ret (*p)(Args...))
{
my_bind(p, make_int_sequence< sizeof...(Args) >{});
}
Usage example of the binder:
#include <iostream>
void foo(double, char, int) { std::cout << __PRETTY_FUNCTION__ << "
"; }
void bar(bool, short) { std::cout << __PRETTY_FUNCTION__ << "
"; }
int main()
{
my_bind(foo);
my_bind(bar);
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…