diff --git a/include/fc/api.hpp b/include/fc/api.hpp index 595b5dd..c9fb41b 100644 --- a/include/fc/api.hpp +++ b/include/fc/api.hpp @@ -3,10 +3,6 @@ #include #include #include -#include -#include -#include -#include // ms visual c++ (as of 2013) doesn't accept the standard syntax for calling a // templated member function (foo->template bar();) @@ -18,8 +14,6 @@ namespace fc { namespace detail { - namespace hana = boost::hana; - /// This metafunction determines whether its template argument is an instantiation of fc::optional template struct is_optional : public std::false_type {}; template struct is_optional> : public std::true_type {}; @@ -38,24 +32,47 @@ namespace fc { struct optionals_callable : public std::function { using std::function::operator(); + template + struct short_pack {}; + /// This metafunction removes the first several types from a variadic parameter pack of types. + /// The first parameter is the number of arguments to remove from the beginning of the pack. + /// All subsequent parameters are types in the list to be cut + /// The result pack_cutter<...>::type is a short_pack + template + struct pack_cutter; + template + struct pack_cutter_impl; + template + struct pack_cutter_impl<0, void, Types...> { + static_assert(all_optionals::value, "All omitted arguments must correspond to optional parameters."); + using type = short_pack; + }; + template + struct pack_cutter_impl, T, Types...> + : public pack_cutter_impl {}; + template + struct pack_cutter : public pack_cutter_impl {}; + template + using pack_cutter_t = typename pack_cutter::type; + + template + R call_function(F&& f, short_pack) { + return f(OptionalTypes()...); + } + /// Overload the function call operator, enabled if the caller provides fewer arguments than there are parameters. /// Pads out the provided arguments with default-constructed optionals, checking that they are indeed optional types template std::enable_if_t operator()(Args... args) { - auto arguments = hana::make_tuple(std::forward(args)...); - // Get the parameter types corresponding to the omitted arguments - auto optional_types = hana::take_back(hana::tuple_t, - hana::size_c); - // Transform the types into default-constructed values, checking that they are optional types - auto optional_values = hana::transform(optional_types, [](auto hanatype) { - using type = std::decay_t; - static_assert(is_optional::value, - "All omitted arguments must correspond to optional parameters."); - return type(); - }); - auto padded_arguments = hana::concat(arguments, optional_values); - return hana::unpack(padded_arguments, - [this](auto... params) { return (*this)(std::forward(params)...); }); + // Partially apply with the arguments provided + auto partial_function = [this, &args...](auto&&... rest) { + return (*this)(std::forward(args)..., std::move(rest)...); + }; + // Cut the provided arguments' types out of the Parameters list, and store the rest in a dummy type + pack_cutter_t...> dummy; + // Pass the partially applied function and the dummy type to another function which can deduce the optional + // types and call the function with default instantiations of those types + return call_function(std::move(partial_function), dummy); } }; }