morganstanley / binlog

A high performance C++ log library, producing structured binary logs
http://opensource.morganstanley.com/binlog/
Apache License 2.0
608 stars 72 forks source link

Support for logging various templated classes #155

Open andrewkcorcoran opened 2 years ago

andrewkcorcoran commented 2 years ago

Such as below. If you control the classes you can have workarounds but if you want to log a class owned by non user code something more is required.

struct Base1{};

template<typename T>
struct Base2 : public Base1
{
    T t;
};

template<typename T, typename S>
struct Derived : public Base2<T>
{
    S s;

   struct Nested{} nested;

   template<typename U>
   struct Nested2{};
};

auto n = Derived<int, double>::Nested2<unsigned int>{};
erenon commented 1 year ago

The closest I got is:

template <typename C>
using ThirdPartyNested = typename third_party::Derived<int, double>::template Nested2<C>;
BINLOG_ADAPT_TEMPLATE((typename C), (ThirdPartyNested<C>))

I'm unable to create a specialization (for CustomTag/CustomSerializer) for a nested template of a template:

error: template parameters not deducible in partial specialization
andrewkcorcoran commented 1 year ago

In an ideal situation it would be great to be able to adapt without having to know the template specialisations e.g. Derived<T, S>::Nested2<U> instead of Derived<int, double>::Nested2<unsigned int>

andrewkcorcoran commented 1 year ago

Also we might want to add a requirement to support nested concepts e.g.

template<SomeConcept T>
struct S
{
   struct S2{};

   template<typename U>
   concept C = requires(U u)
   {...};
};

BINLOG_ADAPT(S<T>);
BINLOG_ADAPT(S<T>::S2);
BINLOG_ADAPT(S<T>::C<U>);
erenon commented 1 year ago

Would you be interested in a solution (based on ADL) that requires adding a symbol to the namespace of the type that is being made loggable? Perhaps we can create something like:

namespace lib {

template<SomeConcept T>
struct S
{
   struct S2{};

   template<typename U>
   concept C = requires(U u)
   {...};
};

template <SomeConcept T, typename U>
void binlog_serializer(S<T>::C<U>) -> SomeSerializer<S<T>::C<U>>;
// ^^^-- this could be produced by a macro

} // namespace lib

(Also a question for #153)

andrewkcorcoran commented 1 year ago

Yea I think that would work for our case.