alexgolec
alexgolec

Reputation: 28252

How can I detect if a type has an operator << overload?

I want to write a generic printing template, so a more specific wording of the question would be: how can I determine if some operator<< method is overloaded for a type?

Upvotes: 4

Views: 432

Answers (2)

songyuanyao
songyuanyao

Reputation: 172894

SFINAE can help you to check if a certain method has been provided.

#include <iostream>

struct Generic {};
struct Printable{};

std::ostream& operator<<(std::ostream& o, const Printable& t) {
    return o;
}

// SFINAE test
typedef char one;
typedef struct { char a[2]; } two;

template <typename T> static one printable_test(std::ostream&o, decltype (o << T{}, 0) ) ;
template <typename T> static two printable_test(...);

template <typename T> bool printable_with(std::ostream& o) { 
    return sizeof(printable_test<T>(o, 0)) == sizeof(one);
}

int main() {
    std::cout << std::boolalpha << printable_with<Generic>(std::cout) << std::endl;
    std::cout << std::boolalpha << printable_with<Printable>(std::cout) << std::endl;
    return 0;
}

LIVE

Some explanations.

There're 2 overloaded function templates printable_test, the overload resolution result of invoking of them in printable_with() will tell the result.

The 1st version takes decltype (o << T{}, 0) as its 2nd parameter, which is valid only when o << T{} is valid, i.e. operator<< on T is provided, and then decltype will take 0 (the last expression of comma expression) as its type, so this version will match the invoking best.

Otherwise, i.e. operator<< on T is not provided, the 2nd version will be adopted.

Upvotes: 1

Yuushi
Yuushi

Reputation: 26040

This can be done using boost.TypeTraits, specifically with has_left_shift. An example:

#include <iostream>
#include "boost/type_traits.hpp"

struct foo
{
    int i;
};

struct bar
{
    int j;
};

std::ostream& operator<<(std::ostream& os, const foo& f)
{
    return os << f.i;
}

int main()
{
    // Prints out 1 == true
    std::cout << boost::has_left_shift<std::ostream&, foo&, std::ostream&>::value << '\n';
    // Prints out 0 == false
    std::cout << boost::has_left_shift<std::ostream&, bar&, std::ostream&>::value << '\n';
}

Watch out for the known issues, however, which are listed down the bottom of the documentation.

Upvotes: 5

Related Questions