The way that the various type classes are implemented all look basically like this:
template <typename T1, typename T2>
static std::optional<M> append(T1&& left, T2&& right) {
static_assert(std::is_same_v<std::remove_cvref_t<T1>, std::optional<M>>, "Argument type should be the same as monoid");
static_assert(std::is_same_v<std::remove_cvref_t<T2>, std::optional<M>>, "Argument type should be the same as monoid");
Is there a reason you chose unconstrained arguments with a static_assert, as opposed to an implementation strategy like:
The former might give you better diagnostics for direct invocations, the latter lets you "bubble up" the constraint to catch it earlier in the call stack.
Great idea, thank you! I think I like your suggestion better than current one (even if current one gives better diagnostics) just because it is cleaner and shorter. I'll definitely try to adopt it.
(This is not necessarily an issue).
The way that the various type classes are implemented all look basically like this:
Is there a reason you chose unconstrained arguments with a
static_assert
, as opposed to an implementation strategy like:The former might give you better diagnostics for direct invocations, the latter lets you "bubble up" the constraint to catch it earlier in the call stack.