It is indeed possible, you just have to "recursively" unpack arguments from the container and pass them to the function on the deepest level:
#include <cstddef> #include <utility> #include <stdexcept> #include <functional> #include <type_traits> #include <vector> #include <iostream> namespace detail { template <std::size_t argument_count> struct arguments_unpacker { template <typename Type, typename Function, typename InputIterator, typename... UnpackedArguments> static Type unpack(Function&& function, InputIterator arguments_begin, InputIterator arguments_end, UnpackedArguments&&... unpacked_arguments) { if (arguments_begin == arguments_end) { throw std::invalid_argument("Not enough arguments."); } return arguments_unpacker<argument_count - 1>::template unpack<Type>(std::forward<Function>(function), std::next(arguments_begin), arguments_end, std::forward<UnpackedArguments>(unpacked_arguments)..., *arguments_begin); } }; template <> struct arguments_unpacker<0> { template <typename Type, typename Function, typename InputIterator, typename... UnpackedArguments> static Type unpack(Function&& function, InputIterator arguments_begin, InputIterator arguments_end, UnpackedArguments&&... unpacked_arguments) { if (arguments_begin != arguments_end) { throw std::invalid_argument("Too many arguments."); } return function(std::forward<UnpackedArguments>(unpacked_arguments)...); } }; template <typename MemberFunction> struct member_function_arity; template <typename Result, typename Class, typename... Arguments> struct member_function_arity<Result(Class::*)(Arguments...)> { static constexpr std::size_t value = sizeof...(Arguments); }; template <typename Result, typename Class, typename... Arguments> struct member_function_arity<Result(Class::*)(Arguments...) const> { static constexpr std::size_t value = sizeof...(Arguments); }; template <typename Function> struct function_arity : member_function_arity<decltype(&Function::operator())> {}; template <typename Result, typename... Arguments> struct function_arity<Result(*)(Arguments...)> { static constexpr std::size_t value = sizeof...(Arguments); }; template <typename Result, typename... Arguments> struct function_arity<std::function<Result(Arguments...)>> { static constexpr std::size_t value = sizeof...(Arguments); }; } template <typename Type, typename InputIterator, typename Function> std::function<Type(InputIterator, InputIterator)> variate(Function function) { using namespace detail; return [function](InputIterator arguments_begin, InputIterator arguments_end) { return arguments_unpacker<function_arity<Function>::value>::template unpack<Type>(function, arguments_begin, arguments_end); }; } namespace demo { double a(double x0) { std::cout << "a(" << x0 << ")\n"; return 0.0; } double b(double x0, double x1) { std::cout << "b(" << x0 << ", " << x1 << ")\n"; return 0.0; } double c(double x0, double x1, double x2) { std::cout << "b(" << x0 << ", " << x1 << ", " << x2 << ")\n"; return 0.0; } auto l = [](double x0) mutable { std::cout << "l(" << x0 << ")\n"; return 0.0; }; void run() { using it = std::vector<double>::const_iterator; auto va = variate<double, it>(&a); auto vb = variate<double, it>(&b); auto vc = variate<double, it>(&c); auto vl = variate<double, it>(l); std::vector<double> a1 = {1.0}; std::vector<double> a2 = {1.0, 2.0}; std::vector<double> a3 = {1.0, 2.0, 3.0}; va(begin(a1), end(a1)); vb(begin(a2), end(a2)); vc(begin(a3), end(a3)); vl(begin(a1), end(a1)); } } int main() { demo::run(); return 0; }
Note that this requres explicitly supplying iterator type. I don't see how it would be possible to remedy that without writing some kind of type erasing any_iterator.