From d7677fca6f2eabb5259a41a4ad6e0c2522162cd5 Mon Sep 17 00:00:00 2001 From: Evan Driscoll Date: Tue, 5 Jun 2018 22:04:48 -0500 Subject: [PATCH] Refactor: some TMP machinery to lead to better overloading The takes_argument trait is coutesy of @N00byEdge --- .../detail/output/fancy_serializer.hpp | 54 ++++++++++++++++++- single_include/nlohmann/json.hpp | 54 ++++++++++++++++++- 2 files changed, 104 insertions(+), 4 deletions(-) diff --git a/include/nlohmann/detail/output/fancy_serializer.hpp b/include/nlohmann/detail/output/fancy_serializer.hpp index f40fb7532..3387fdebc 100644 --- a/include/nlohmann/detail/output/fancy_serializer.hpp +++ b/include/nlohmann/detail/output/fancy_serializer.hpp @@ -29,6 +29,46 @@ namespace nlohmann { +namespace details +{ +// Some metaprogramming stuff. The point here is to distinguish +// functions and function objects that take 'json' and +// 'json_pointer' as the first argument. This can't be done +// conventionally because there are implicit conversions in both +// directions, so a function type that matches one will match the +// other. (The conversion from json to json_pointer doesn't really +// exist if you try to use it, but it does in the SFIANE context.) +// +// So we define takes_argument to see if Func(Arg) is +// not only legal but without undergoing any conversions on +// Arg. That's where 'metawrapper' comes into play. We actually +// check if Func(metawrapper) is legal. That takes up the one +// implicit conversion that's allowed. +// +// See also the uses below. + +template struct make_void +{ + typedef void type; +}; +template using void_t = typename make_void::type; + +template +struct metawrapper +{ + operator T const& (); +}; + +template +struct takes_arguments_impl : std::false_type { }; + +template +struct takes_arguments_impl()(metawrapper()...))>, F, Args...> : std::true_type { }; + +template +struct takes_arguments : takes_arguments_impl { }; +} + struct print_style { unsigned int indent_step = 4; @@ -109,10 +149,12 @@ class basic_print_stylizer return styles.back().second; } + // Predicate is conceptually 'bool (json)' here template - print_style& register_style_object_pred( + auto register_style_object_pred( Predicate p, print_style style = print_style()) + -> typename std::enable_if::value, print_style&>::type { auto wrapper = [p](const json_pointer_t&, const BasicJsonType & j) { @@ -122,10 +164,18 @@ class basic_print_stylizer return styles.back().second; } + // Predicate is conceptually 'bool (json_pointer)' here... + // + // ...But we have to 'json' instead (or rather, BasicJsonType) + // because json has an apparent (in the SFIANE context) implicit + // conversion from and two everything. Including + // 'metawrapper'. So if you pass 'bool (json)', it + // will look like it can pass a metawrapper to it template - print_style& register_style_context_pred( + auto register_style_context_pred( Predicate p, print_style style = print_style()) + -> typename std::enable_if < !details::takes_arguments::value, print_style& >::type { auto wrapper = [p](const json_pointer_t& c, const BasicJsonType&) { diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index d72fbf1a2..a3ec2705b 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -10834,6 +10834,46 @@ class json_pointer namespace nlohmann { +namespace details +{ +// Some metaprogramming stuff. The point here is to distinguish +// functions and function objects that take 'json' and +// 'json_pointer' as the first argument. This can't be done +// conventionally because there are implicit conversions in both +// directions, so a function type that matches one will match the +// other. (The conversion from json to json_pointer doesn't really +// exist if you try to use it, but it does in the SFIANE context.) +// +// So we define takes_argument to see if Func(Arg) is +// not only legal but without undergoing any conversions on +// Arg. That's where 'metawrapper' comes into play. We actually +// check if Func(metawrapper) is legal. That takes up the one +// implicit conversion that's allowed. +// +// See also the uses below. + +template struct make_void +{ + typedef void type; +}; +template using void_t = typename make_void::type; + +template +struct metawrapper +{ + operator T const& (); +}; + +template +struct takes_arguments_impl : std::false_type { }; + +template +struct takes_arguments_impl()(metawrapper()...))>, F, Args...> : std::true_type { }; + +template +struct takes_arguments : takes_arguments_impl { }; +} + struct print_style { unsigned int indent_step = 4; @@ -10914,10 +10954,12 @@ class basic_print_stylizer return styles.back().second; } + // Predicate is conceptually 'bool (json)' here template - print_style& register_style_object_pred( + auto register_style_object_pred( Predicate p, print_style style = print_style()) + -> typename std::enable_if::value, print_style&>::type { auto wrapper = [p](const json_pointer_t&, const BasicJsonType & j) { @@ -10927,10 +10969,18 @@ class basic_print_stylizer return styles.back().second; } + // Predicate is conceptually 'bool (json_pointer)' here... + // + // ...But we have to 'json' instead (or rather, BasicJsonType) + // because json has an apparent (in the SFIANE context) implicit + // conversion from and two everything. Including + // 'metawrapper'. So if you pass 'bool (json)', it + // will look like it can pass a metawrapper to it template - print_style& register_style_context_pred( + auto register_style_context_pred( Predicate p, print_style style = print_style()) + -> typename std::enable_if < !details::takes_arguments::value, print_style& >::type { auto wrapper = [p](const json_pointer_t& c, const BasicJsonType&) {