Skip to content

compile-time check if adaptor for type exists #1051

@timblechmann

Description

@timblechmann

more a question than a bug, but something that i've been wondering without having found a good answer, yet:

i'd like to detect at compile time via a constexpr function if an adaptor for a specific type exists:

template <typename T>
constexpr bool msgpack_can_pack();

currently we have:

template <typename T, typename Enabler>
struct convert {
    msgpack::object const& operator()(msgpack::object const& o, T& v) const;
};

operator() is either implemented by a specialization or it is using the default implementation at:

template <typename T, typename Enabler>
inline
msgpack::object const&
adaptor::convert<T, Enabler>::operator()(msgpack::object const& o, T& v) const {
    v.msgpack_unpack(o.convert());
    return o;
}

so afaict we may need two answer two question:

  • can we use enable_if to check if the operator() can be implemented for a specific type?
  • can we check if operator() exists in order to implement msgpack_can_pack?

thoughts?


i've done a few experiments:

diff --git a/include/msgpack/v1/adaptor/adaptor_base.hpp b/include/msgpack/v1/adaptor/adaptor_base.hpp
index 489362b..b2291ec 100644
--- a/include/msgpack/v1/adaptor/adaptor_base.hpp
+++ b/include/msgpack/v1/adaptor/adaptor_base.hpp
@@ -18,17 +18,43 @@ namespace msgpack {
 MSGPACK_API_VERSION_NAMESPACE(v1) {
 /// @endcond
 
 
 namespace adaptor {
 
+namespace impl {
+
+template < typename T >
+using msgpack_unpack_t
+    = decltype( std::declval< T >().msgpack_unpack( std::declval< msgpack::object::implicit_type >() ) );
+
+template < typename T, typename = std::void_t<> >
+struct has_msgpack_unpack : std::false_type
+{};
+
+template < typename T >
+struct has_msgpack_unpack< T, std::void_t< msgpack_unpack_t< T > > > : std::true_type
+{};
+
+template < typename T >
+inline constexpr bool has_msgpack_unpack_v = has_msgpack_unpack< T >::value;
+
+} // namespace impl
+
+
 // Adaptor functors
 
-template <typename T, typename Enabler>
-struct convert {
-    msgpack::object const& operator()(msgpack::object const& o, T& v) const;
+template<typename T, typename Enabler>
+struct convert
+{
+};
+
+template<typename T>
+struct convert<T, std::enable_if_t<impl::has_msgpack_unpack_v<T>>>
+{
+    msgpack::object const &operator()(msgpack::object const &o, T &v) const;
 };
 
 template <typename T, typename Enabler>
 struct pack {
     template <typename Stream>
     msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, T const& v) const;
diff --git a/include/msgpack/v1/object.hpp b/include/msgpack/v1/object.hpp
index fda54be..a9ac15a 100644
--- a/include/msgpack/v1/object.hpp
+++ b/include/msgpack/v1/object.hpp
@@ -637,16 +637,16 @@ struct packer_serializer {
         return o;
     }
 };
 } // namespace detail
 
 // Adaptor functors' member functions definitions.
-template <typename T, typename Enabler>
+template <typename T>
 inline
 msgpack::object const&
-adaptor::convert<T, Enabler>::operator()(msgpack::object const& o, T& v) const {
+adaptor::convert<T, std::enable_if_t<adaptor::impl::has_msgpack_unpack_v<T>>>::operator()(msgpack::object const& o, T& v) const {
     v.msgpack_unpack(o.convert());
     return o;
 }
 
 template <typename T, typename Enabler>
 template <typename Stream>

this would allow me to write something like:

template < typename T, typename = void >
struct has_msgpack_convert_helper : std::false_type
{};

template < typename T >
struct has_msgpack_convert_helper< T,
                                   std::void_t< decltype( std::declval< msgpack::v3::adaptor::convert< T > >()(
                                       std::declval< msgpack::object const& >(), std::declval< T& >() ) ) > >
    : std::true_type
{};

template < typename T >
constexpr bool has_msgpack_convert = has_msgpack_convert_helper< T >::value;

any thoughts on such functionality in the library?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions