lundi 23 octobre 2017

Overriding operator<< for all types

I'm a bit annoyed with compilation errors which arise when I try to write std::cout << x, and left shift operator it not defined for x. Can't convert x to this, can't convert x to that... Several screens of useless error messages.

I want to specialize operator<<(std::ostream&, const T&) for all types which do not yet have such operator defined. Inside I could put a, say, static assert and make compilation error message much clearer than it is now.

My first attempt was the following.

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

template<typename T>
struct Has<T, decltype(void(
            std::declval<std::ostream&>() << std::declval<T>()
))> : public std::true_type {};

template<typename T>
auto operator<<(std::ostream& out, const T&)
    -> typename std::enable_if<
        !Has<T>::value,
        std::ostream&>::type
{
    return out << "my operator";
}

It fails to compile because maximum template depth is exceeded. Indeed, my operator<< calls to Has specialization which in order calls to operator<<, where my overload is examined once again, so on, so on, so on.

The simplest version doesn't work as well: ambiguous overload for std::ostream& << const char*. Well, expected.

template<typename T>
std::ostream& operator<<(std::ostream& out, const T&)
{
    return out << "my operator";
}

How can I accomplish the task? Or, in general, how can I define the function for all argument types but for those which can already be passed to the function?

Aucun commentaire:

Enregistrer un commentaire