Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion src/Corrade/Utility/DebugStl.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,32 @@ template<class ...Args> Debug& operator<<(Debug& debug, const std::tuple<Args...

namespace Implementation {

template<typename T>
typename std::add_lvalue_reference<T>::type declare_lvalue_reference() noexcept;
Comment thread
rune-scape marked this conversation as resolved.
Outdated

template<typename T>
struct has_ostream_operator {
private:
template<typename C>
static constexpr auto check(C *) ->
typename std::is_same<
decltype(declare_lvalue_reference<std::ostream>() << std::declval<C>()),
std::add_lvalue_reference<std::ostream>::type
>::type;

template<typename>
static constexpr std::false_type check(...);

public:
static constexpr bool value = decltype(check<T>(nullptr))::value;
};

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a (admittedly weirdly named) CORRADE_HAS_TYPE(className, typeExpression) macro that already contains the above functionality, but your variant seems to be a lot simpler than what I stole from somewhere back in the day :) If I fix the macro to have the second parameter variadic (so the comma doesn't break it), I think we could then reduce the above to be just this (containing the potentially hard-to-understand template magic in a single place):

CORRADE_HAS_TYPE(HasOstreamOperator, typename std::is_same<
    decltype(declareLvalueReference<std::ostream>() << std::declval<C>()),
    std::add_lvalue_reference<std::ostream>::type
>::type)

(Also adapting the naming to what Corrade uses for type traits.) I hope I didn't overlook something that would make this impossible tho.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CORRADE_HAS_TYPE() is fixed to allow this in 8d4eb5b, and I think it would work with a minor change:

CORRADE_HAS_TYPE(HasOstreamOperator, typename std::enable_if<std::is_same<
    decltype(declareLvalueReference<std::ostream>() << std::declval<C>()),
    std::add_lvalue_reference<std::ostream>::type
>::value>::type)

I assume you have some way to test the infinite recursion already -- can you confirm? :)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes! works perfectly. A very useful macro too


/* Used by Debug::operator<<(Implementation::DebugOstreamFallback&&) */
struct DebugOstreamFallback {
template<class T> /*implicit*/ DebugOstreamFallback(const T& t): applier(&DebugOstreamFallback::applyImpl<T>), value(&t) {}
template<
class T,
typename = typename std::enable_if<has_ostream_operator<T>::value>::type
> /*implicit*/ DebugOstreamFallback(const T& t): applier(&DebugOstreamFallback::applyImpl<T>), value(&t) {}

void apply(std::ostream& s) const {
(this->*applier)(s);
Expand Down