diff --git a/include/toml11/visit.hpp b/include/toml11/visit.hpp index d97344b..715b403 100644 --- a/include/toml11/visit.hpp +++ b/include/toml11/visit.hpp @@ -8,22 +8,68 @@ namespace toml { -template -cxx::return_type_of_t::boolean_type&> -visit(Visitor&& visitor, const basic_value& v) +namespace detail +{ + +template +using visit_result_t = decltype(std::declval()(std::declval().as_boolean() ...)); + +template +struct front_binder +{ + template + auto operator()(Args&& ... args) -> decltype(std::declval()(std::declval(), std::forward(args)...)) + { + return func(std::move(front), std::forward(args)...); + } + F func; + T front; +}; + +template +front_binder, cxx::remove_cvref_t> +bind_front(F&& f, T&& t) +{ + return front_binder, cxx::remove_cvref_t>{ + std::forward(f), std::forward(t) + }; +} + +template +visit_result_t&, Args...> +visit_impl(Visitor&& visitor, const basic_value& v, Args&& ... args); + +template +visit_result_t&, Args...> +visit_impl(Visitor&& visitor, basic_value& v, Args&& ... args); + +template +visit_result_t, Args...> +visit_impl(Visitor&& visitor, basic_value&& v, Args&& ... args); + + +template +visit_result_t visit_impl(Visitor&& visitor) +{ + return visitor(); +} + +template +visit_result_t&, Args...> +visit_impl(Visitor&& visitor, basic_value& v, Args&& ... args) { switch(v.type()) { - case value_t::boolean : {return visitor(v.as_boolean ());} - case value_t::integer : {return visitor(v.as_integer ());} - case value_t::floating : {return visitor(v.as_floating ());} - case value_t::string : {return visitor(v.as_string ());} - case value_t::offset_datetime: {return visitor(v.as_offset_datetime());} - case value_t::local_datetime : {return visitor(v.as_local_datetime ());} - case value_t::local_date : {return visitor(v.as_local_date ());} - case value_t::local_time : {return visitor(v.as_local_time ());} - case value_t::array : {return visitor(v.as_array ());} - case value_t::table : {return visitor(v.as_table ());} + case value_t::boolean : {return visit_impl(bind_front(visitor, std::ref(v.as_boolean ())), std::forward(args)...);} + case value_t::integer : {return visit_impl(bind_front(visitor, std::ref(v.as_integer ())), std::forward(args)...);} + case value_t::floating : {return visit_impl(bind_front(visitor, std::ref(v.as_floating ())), std::forward(args)...);} + case value_t::string : {return visit_impl(bind_front(visitor, std::ref(v.as_string ())), std::forward(args)...);} + case value_t::offset_datetime: {return visit_impl(bind_front(visitor, std::ref(v.as_offset_datetime())), std::forward(args)...);} + case value_t::local_datetime : {return visit_impl(bind_front(visitor, std::ref(v.as_local_datetime ())), std::forward(args)...);} + case value_t::local_date : {return visit_impl(bind_front(visitor, std::ref(v.as_local_date ())), std::forward(args)...);} + case value_t::local_time : {return visit_impl(bind_front(visitor, std::ref(v.as_local_time ())), std::forward(args)...);} + case value_t::array : {return visit_impl(bind_front(visitor, std::ref(v.as_array ())), std::forward(args)...);} + case value_t::table : {return visit_impl(bind_front(visitor, std::ref(v.as_table ())), std::forward(args)...);} case value_t::empty : break; default: break; } @@ -31,22 +77,22 @@ visit(Visitor&& visitor, const basic_value& v) "does not have any valid type.", v.location(), "here"), v.location()); } -template -cxx::return_type_of_t::boolean_type&> -visit(Visitor&& visitor, basic_value& v) +template +visit_result_t&, Args...> +visit_impl(Visitor&& visitor, const basic_value& v, Args&& ... args) { switch(v.type()) { - case value_t::boolean : {return visitor(v.as_boolean ());} - case value_t::integer : {return visitor(v.as_integer ());} - case value_t::floating : {return visitor(v.as_floating ());} - case value_t::string : {return visitor(v.as_string ());} - case value_t::offset_datetime: {return visitor(v.as_offset_datetime());} - case value_t::local_datetime : {return visitor(v.as_local_datetime ());} - case value_t::local_date : {return visitor(v.as_local_date ());} - case value_t::local_time : {return visitor(v.as_local_time ());} - case value_t::array : {return visitor(v.as_array ());} - case value_t::table : {return visitor(v.as_table ());} + case value_t::boolean : {return visit_impl(bind_front(visitor, std::cref(v.as_boolean ())), std::forward(args)...);} + case value_t::integer : {return visit_impl(bind_front(visitor, std::cref(v.as_integer ())), std::forward(args)...);} + case value_t::floating : {return visit_impl(bind_front(visitor, std::cref(v.as_floating ())), std::forward(args)...);} + case value_t::string : {return visit_impl(bind_front(visitor, std::cref(v.as_string ())), std::forward(args)...);} + case value_t::offset_datetime: {return visit_impl(bind_front(visitor, std::cref(v.as_offset_datetime())), std::forward(args)...);} + case value_t::local_datetime : {return visit_impl(bind_front(visitor, std::cref(v.as_local_datetime ())), std::forward(args)...);} + case value_t::local_date : {return visit_impl(bind_front(visitor, std::cref(v.as_local_date ())), std::forward(args)...);} + case value_t::local_time : {return visit_impl(bind_front(visitor, std::cref(v.as_local_time ())), std::forward(args)...);} + case value_t::array : {return visit_impl(bind_front(visitor, std::cref(v.as_array ())), std::forward(args)...);} + case value_t::table : {return visit_impl(bind_front(visitor, std::cref(v.as_table ())), std::forward(args)...);} case value_t::empty : break; default: break; } @@ -54,22 +100,22 @@ visit(Visitor&& visitor, basic_value& v) "does not have any valid type.", v.location(), "here"), v.location()); } -template -cxx::return_type_of_t::boolean_type&&> -visit(Visitor&& visitor, basic_value&& v) +template +visit_result_t, Args...> +visit_impl(Visitor&& visitor, basic_value&& v, Args&& ... args) { switch(v.type()) { - case value_t::boolean : {return visitor(std::move(v.as_boolean ()));} - case value_t::integer : {return visitor(std::move(v.as_integer ()));} - case value_t::floating : {return visitor(std::move(v.as_floating ()));} - case value_t::string : {return visitor(std::move(v.as_string ()));} - case value_t::offset_datetime: {return visitor(std::move(v.as_offset_datetime()));} - case value_t::local_datetime : {return visitor(std::move(v.as_local_datetime ()));} - case value_t::local_date : {return visitor(std::move(v.as_local_date ()));} - case value_t::local_time : {return visitor(std::move(v.as_local_time ()));} - case value_t::array : {return visitor(std::move(v.as_array ()));} - case value_t::table : {return visitor(std::move(v.as_table ()));} + case value_t::boolean : {return visit_impl(bind_front(visitor, std::move(v.as_boolean ())), std::forward(args)...);} + case value_t::integer : {return visit_impl(bind_front(visitor, std::move(v.as_integer ())), std::forward(args)...);} + case value_t::floating : {return visit_impl(bind_front(visitor, std::move(v.as_floating ())), std::forward(args)...);} + case value_t::string : {return visit_impl(bind_front(visitor, std::move(v.as_string ())), std::forward(args)...);} + case value_t::offset_datetime: {return visit_impl(bind_front(visitor, std::move(v.as_offset_datetime())), std::forward(args)...);} + case value_t::local_datetime : {return visit_impl(bind_front(visitor, std::move(v.as_local_datetime ())), std::forward(args)...);} + case value_t::local_date : {return visit_impl(bind_front(visitor, std::move(v.as_local_date ())), std::forward(args)...);} + case value_t::local_time : {return visit_impl(bind_front(visitor, std::move(v.as_local_time ())), std::forward(args)...);} + case value_t::array : {return visit_impl(bind_front(visitor, std::move(v.as_array ())), std::forward(args)...);} + case value_t::table : {return visit_impl(bind_front(visitor, std::move(v.as_table ())), std::forward(args)...);} case value_t::empty : break; default: break; } @@ -77,5 +123,14 @@ visit(Visitor&& visitor, basic_value&& v) "does not have any valid type.", v.location(), "here"), v.location()); } +} // detail + +template +detail::visit_result_t +visit(Visitor&& visitor, Args&& ... args) +{ + return detail::visit_impl(std::forward(visitor), std::forward(args)...); +} + } // toml #endif // TOML11_VISIT_HPP