diff --git a/src/json.hpp b/src/json.hpp index 4c6d8671..1188ead4 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -715,27 +715,81 @@ void from_json(Json const &j, ArithmeticType &val) throw std::domain_error("type must be number, but is " + type_name(j)); } +template +constexpr auto has_adl_from_json(int) -> decltype(from_json(std::declval(), std::declval()), true) +{ + return true; +} + +template +constexpr bool has_adl_from_json(long) +{ + return false; +} + +template +constexpr auto has_adl_to_json(int) -> decltype(to_json(std::declval(), std::declval()), true) +{ + return true; +} + +template +constexpr bool has_adl_to_json(long) +{ + return false; +} + struct to_json_fn { - template - constexpr auto operator()(Json&& j, T&& val) const + private: + template (0), int> = 0> + auto operator()(Json&& j, T&& val) const noexcept(noexcept(to_json(std::forward(j), std::forward(val)))) -> decltype(to_json(std::forward(j), std::forward(val)), void()) { return to_json(std::forward(j), std::forward(val)); } + + template (0), int> = 0> + void operator()(Json&&, T&&) const noexcept + { + static_assert(has_adl_to_json(0), "to_json method in T's namespace can not be called"); + } + +public: + template + void operator()(Json &j, T &&val) const + noexcept(noexcept(std::declval().call(0, j, std::forward(val)))) + { + return call(0, j, std::forward(val)); + } }; struct from_json_fn { - template - constexpr auto operator()(Json&& j, T& val) const + private: + template (0), int> = 0> + auto operator()(Json&& j, T& val) const noexcept(noexcept(from_json(std::forward(j), val))) -> decltype(from_json(std::forward(j), val), void()) { return from_json(std::forward(j), val); } + + template (0), int> = 0> + void operator()(Json&&, T&) const noexcept + { + static_assert(has_adl_from_json(0), "from_json method in T's namespace can not be called"); + } + +public: + template + void operator()(Json const &j, T &val) const + noexcept(noexcept(std::declval().call(0, j, val))) + { + return call(0, j, val); + } }; /*! @@ -757,7 +811,6 @@ struct DecimalSeparator : std::numpunct return '.'; } }; - } // taken from ranges-v3