strong_type icon indicating copy to clipboard operation
strong_type copied to clipboard

Comments requested about modifier: qdebuggable (Qt debug)

Open miemoe opened this issue 6 months ago • 0 comments

I tried to add a modifier, that accesses more functionality. I program a lot with the Qt Framework and though how to make a typical line:

int foo = 0;
qDebug() << foo;

available for a strong typed int.

A simple

using myint = strong::type<int, struct my_int_>;
myint foo{0};
qDebug() << foo;

does not work, it won't compile because QDebug does not know anything about myint.

One way would be to convert it back to its base type

using myint = strong::type<int, struct my_int_>;
myint foo{0};
qDebug() << (int)foo;

but this won't work, as the conversion to int has to be added as a modifier:

using myint = strong::type<int, struct my_int_, strong::convertible_to<int>>;
myint foo{0};
qDebug() << (int)foo;

However, this does not

  • look nice and
  • if I change the underlying type to something more appropriate for the strong type, it might even not be convertable to int anymore!

I could get rid of the (int) C-style converter if I'd use the modifier: strong::implicitly_convertible_to<Ts...> but this only helps for the first problem. And it would feel like washing away the "strong" in Strong Types ...

Looking at the documentation of how QDebug in Qt works I tried to add a new modifier: qdebuggable.

I would like to kindly request comments from you, if the modifier is appropriate, to what I want to reach:

#pragma once

#include <strong_type/type.hpp>

#include <QDebug>

namespace strong
{
struct qdebuggable
   {
      template <typename T, typename = void>
      class modifier {
            static_assert(impl::always_false<T>,
            "Underlying type must be qdebuggable");
         };
   };


template <typename T, typename Tag, typename ... M>
class qdebuggable::modifier<
      ::strong::type<T, Tag, M...>,
      impl::void_t<decltype(operator<<(std::declval<QDebug>(), std::declval<const T&>()))>
>
   {
   using type = ::strong::type<T, Tag, M...>;
   public:
   friend
         auto
         operator<<(
            QDebug dbg,
            const type& value)
         noexcept(noexcept(operator<<(std::declval<QDebug>(), std::declval<const T&>())))
         -> decltype(operator<<(std::declval<QDebug>(), std::declval<const T&>()))
      {
         dbg << value_of(value);
         return dbg;
      }
   };
}

I tried it with some base types that are supported by QDebug directly and also by User Defined Types as base type where a QDebug stream operator was added to. As the QLoggingCategory also relies on QDebug mechanism all Qt Debugging seems to work fine.

The Qt Framwork also offers some similar patterns with QDataStream and QTextStream. Probably there are more...

But befor I sit on these, I'd like to be sure that this first modifier is "right".

Thanks.

miemoe avatar Jun 19 '25 13:06 miemoe