Refactor: some TMP machinery to lead to better overloading

The takes_argument trait is coutesy of @N00byEdge
This commit is contained in:
Evan Driscoll 2018-06-05 22:04:48 -05:00
parent 680a85b7a2
commit d7677fca6f
2 changed files with 104 additions and 4 deletions

View File

@ -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<json>' 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<Func, Arg> 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<Arg>) is legal. That takes up the one
// implicit conversion that's allowed.
//
// See also the uses below.
template<typename... Ts> struct make_void
{
typedef void type;
};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
template <typename T>
struct metawrapper
{
operator T const& ();
};
template <typename = void, typename F = void, typename ...Args>
struct takes_arguments_impl : std::false_type { };
template <typename F, typename ...Args>
struct takes_arguments_impl<void_t<decltype(std::declval<F>()(metawrapper<Args>()...))>, F, Args...> : std::true_type { };
template<typename F, typename ...Args>
struct takes_arguments : takes_arguments_impl<void, F, Args...> { };
}
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 <typename Predicate>
print_style& register_style_object_pred(
auto register_style_object_pred(
Predicate p,
print_style style = print_style())
-> typename std::enable_if<details::takes_arguments<Predicate, BasicJsonType>::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<json_pointer>'. So if you pass 'bool (json)', it
// will look like it can pass a metawrapper<json_pointer> to it
template <typename Predicate>
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<Predicate, BasicJsonType>::value, print_style& >::type
{
auto wrapper = [p](const json_pointer_t& c, const BasicJsonType&)
{

View File

@ -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<json>' 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<Func, Arg> 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<Arg>) is legal. That takes up the one
// implicit conversion that's allowed.
//
// See also the uses below.
template<typename... Ts> struct make_void
{
typedef void type;
};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
template <typename T>
struct metawrapper
{
operator T const& ();
};
template <typename = void, typename F = void, typename ...Args>
struct takes_arguments_impl : std::false_type { };
template <typename F, typename ...Args>
struct takes_arguments_impl<void_t<decltype(std::declval<F>()(metawrapper<Args>()...))>, F, Args...> : std::true_type { };
template<typename F, typename ...Args>
struct takes_arguments : takes_arguments_impl<void, F, Args...> { };
}
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 <typename Predicate>
print_style& register_style_object_pred(
auto register_style_object_pred(
Predicate p,
print_style style = print_style())
-> typename std::enable_if<details::takes_arguments<Predicate, BasicJsonType>::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<json_pointer>'. So if you pass 'bool (json)', it
// will look like it can pass a metawrapper<json_pointer> to it
template <typename Predicate>
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<Predicate, BasicJsonType>::value, print_style& >::type
{
auto wrapper = [p](const json_pointer_t& c, const BasicJsonType&)
{