Here is my code:
#include <iostream>
#include <type_traits>
#include <functional>
#include <tuple>
namespace meta {
template <bool B, bool... Bs>
struct all_true {
enum : bool { value = B && all_true<Bs...>::value };
};
template <bool B>
struct all_true<B> {
enum : bool { value = B };
};
template <typename Fn, typename... Args>
struct is_partial_t_nothrow_ctor {
enum : bool {
a = std::is_nothrow_constructible<Fn, Fn&&>::value,
b = all_true<std::is_nothrow_constructible<Args, Args&&>::value...>::value,
value = a && b
};
};
}
template <typename Fn, typename... Args>
class partial_t {
private:
Fn fn_;
std::tuple<Args...> args_;
template <std::size_t... Is, typename... ExArgs>
decltype(auto) op_parens_impl(std::index_sequence<Is...>, ExArgs&&... ex_args) {
fn_(std::forward<Args>(std::get<Is>(args_))...,
std::forward<ExArgs>(ex_args)...);
}
template <typename... ExArgs>
decltype(auto) op_parens_impl(ExArgs&&... ex_args) {
return op_parens_impl(
std::index_sequence_for<Args...>(), std::forward<ExArgs>(ex_args)...);
}
public:
partial_t(Fn&& fn, Args&&... args)
noexcept(meta::is_partial_t_nothrow_ctor<Fn, Args...>::value)
: fn_(std::forward<Fn>(fn)), args_(std::forward_as_tuple(args...))
{}
template <typename... ExArgs>
decltype(auto) operator()(ExArgs&&... ex_args)
// noexcept(?)
{
return op_parens_impl(std::forward<ExArgs>(ex_args)...);
}
};
template <typename Fn, typename... Args>
auto partial(Fn&& fn, Args&&... args)
noexcept(meta::is_partial_t_nothrow_ctor<Fn, Args...>::value)
{
return partial_t<Fn, Args...>(std::forward<Fn>(fn), std::forward<Args>(args)...);
}
Test code:
void test(int x, int y, int z) {
std::cout << "my first number is " << x << std::endl;
std::cout << "my second number is " << y << std::endl;
std::cout << "my favorite number is " << z << std::endl;
}
int main() {
auto f = partial(test, 5, 3);
f(7);
}
which outputs:
my first number is 5
my second number is 3
my favorite number is 7
The function partial takes a function object as its first parameter and then a number of arguments. It returns a function object which binds these arguments to the input function as its first parameters, then the rest of the arguments are provided later when this partial function is invoked.