I’ve got a simple wrapper around bind_front
that fails for some reason even before I add my additional code
Here’s the snippet
#include <iostream>
#include <functional>
volatile int a1;
volatile int a2;
volatile int a3;
volatile int a4;
volatile int a5;
void foo(int b1, int b2, int b3, int b4, int b5)
{
a1 += b1;
a2 += b2;
a3 += b3;
a4 += b4;
a5 += b5;
}
template <class P, class... Args>
std::function<void(P)> my_bind(void (*method)(Args..., P), Args... args)
{
auto bound = std::bind(method, std::forward<Args>(args)..., std::placeholders::_1);;
return bound;
}
int main(void)
{
std::function<void(int)> a = my_bind(&foo, 1, 2, 3, 4);
std::cout << a1 << " " << a2 << " " << a3 << " " << a4 << " " << a5 << std::endl;
a(5);
std::cout << a1 << " " << a2 << " " << a3 << " " << a4 << " " << a5 << std::endl;
return 0;
}
With clang 18.0.1 I get
<source>:28:34: error: no matching function for call to 'my_bind'
28 | std::function<void(int)> a = my_bind(&foo, 1, 2, 3, 4);
| ^~~~~~~
<source>:20:24: note: candidate template ignored: failed template argument deduction
20 | std::function<void(P)> my_bind(void (*method)(Args..., P), Args... args)
| ^
1 error generated.
Compiler returned: 1
am I missing something?
If i remove the param P
and the placeholder then things work for param less return types
C++ won’t deduce anything after ...
. ...
eats all.
The Args..., P
blocks all possibility of deduction occuring. It won’t do “ok, there are 7 items, so 6 go into Args...
and the leftover is P
“; instead, it will say “stuff after ...
, give up immediately.”.
The standard could describe how to solve for deducing stuff after ...
, but the standard does not, so it doesn’t work. (How exactly that would work is out of scope for an answer here, as would any problems that would develop if it was allowed).
Now, C++ template metaprogramming is easily powerful enough to actually do what you seem to want. But you have to write the logic yourself.
You’d start with this:
template <class...A0s, class...A1s>
auto my_bind(void (*method)(A0s...), A1s... args);
then write code that “subtracts” the elements of A1s...
from A0s...
; a really naive one would be to just count and drop them:
template<class...Ts>
struct types {using type=types;};
template<std::size_t N, class...Ts>
struct drop_types;
template<0, class...Ts>
struct drop_types:types<Ts...>{};
template<std::size_t N, class T0, class...Ts>
struct drop_types<N, T0, Ts...>:drop_types<N-1, Ts...>{};
template<std::size_t N, class...Ts>
using drop_types_t = typename drop_types<N,Ts...>::type;
now we have drop_types_t<sizeof...(A1s), A0s...>
as types<A,B,C>
from the “tail” of A0s...
.
template<class Sig>
struct build_func;
template<class R, class...Args>
struct build_func<R(Args...)> {
template<class...Ts>
using append = build_func<R, Args..., Ts...>;
using type = std::function<R(Args...)>;
};
template<template<class...>class Z, class types>
struct apply_types;
template<template<class...>class Z, class types>
using apply_types_t = typename apply_types<Z,types>::type;
template<template<class...>class Z, class...Ts>
struct apply_types<Z, types<Ts...>> {
using type = Z<Ts...>;
};
then put it together:
template <class...A0s, class...A1s>
auto my_bind(void (*method)(A0s...), A1s... args)
-> apply_types_t< template build_func<void()>::append, drop_types_t<sizeof...(A1s), A0s...> >
the implementation could look like:
{
return [=](auto&&...extra)->void {
return method( args..., std::forward<decltype(extra)>(extra)... );
};
}
tpyos abound above, so use with caution, but the design should be sound.