9

I'm trying to do it this way:

template <typename T>
ostream &operator<<(ostream &os, T &arr)
{ /*...*/ }

But can T represent an array? Is it correct to overload the << operator for an array?


EDIT:

According to Kerrek SB's advice, here is my implementation for <<:

template <typename T, unsigned int N>
ostream &operator<<(ostream &os, const T (&arr)[N])
{
    int i;
    for(i = 0; i < N; i++)
        os << arr[i] << " ";
    os << endl;
    return os;
}

Is my implementation right? I got a compilation error.

0

2 Answers 2

10

You could do this:

template <typename T, unsigned int N>
std::ostream & operator<<(std::ostream & os, const T (&arr)[N])
{
  // ..
  return os;
}

This works only for compile-time arrays, of course. Note that you are not allowed to instantiate this template when T is a built-in type or a type in the std namespace!

Probably best to make this inline if possible, since you'll cause a separate instantiation for every N. (The pretty printer has an example of this.)

You will notice, though, that the blanket template introduces an ambiguity, because os << "Hello" now has two possible overloads: the template matching const char (&)[6], and the (non-template) overload for the decay-to-pointer const char *, which both have identical conversion sequences. We can resolve this by disabling our overload for char arrays:

#include <ostream>
#include <type_traits>

template <typename T, unsigned int N>
typename std::enable_if<!std::is_same<T, char>::value, std::ostream &>::type
operator<<(std::ostream & os, const T (&arr)[N])
{
  // ..
  return os;
}

In fact, to be even more general you can also make the basic_ostream parameters template parameters:

template <typename T, unsigned int N, typename CTy, typename CTr>
typename std::enable_if<!std::is_same<T, char>::value,
                        std::basic_ostream<CTy, CTr> &>::type
operator<<(std::basic_ostream<CTy, CTr> & os, const T (&arr)[N])
{
  // ..
  return os;
}

In view of the fact that T must be a user-defined type, you could even replace is_same<T, char> with is_fundamental<T> to get a bit more checking (but users still must not use this for arrays of standard library types).

Sign up to request clarification or add additional context in comments.

17 Comments

thanks, but I don't understand why it cause a separate instantiation for every N if not implemented inline?
Well, it's a template, so every template instance may end up as a separate function in your binary. If you inline, you can possibly avoid the function call entirely, although this is ultimately up to the compiler.
got it. With this operator<< having 2 template args, how could I specify the second arg N? Apparently I cannot just simply use "cout << ar;", can I?
Try it :-) This is a template function, so template parameter deduction applies and you don't have to specify anything: int a[10]; std::cout << a;.
well, I got compile-error, I will edit my post to add my implementation for <<.
|
3

Another way you could do this would be something like the following:

template<typename T>
ostream& operator<<(ostream &out, const std::pair<T, int>& array)
{
    //...code
    return out;
}

Where T will take a pointer to an array (i.e., it will be the pointer-type that the array will decay into), and the int portion of the pair would be the size of the array. You could then use it like the following:

int array[10];
//...some code that initializes array, etc.

cout << make_pair(array, 10);

One plus with this method is it will also work for dynamic arrays (i.e., arrays you allocate on the heap, etc.)

2 Comments

I have a very faint feeling that you may get in trouble with ADL here if your T isn't a user-defined type, though I can't be sure.
I tested it with a build-in type like int ... seemed to work just fine ... I can't think why this would conflict with ADL rules. If you have a std::pair<T, U> object, the template should be capable of deducing the type T, and rejecting any instantiations using a std::pair<T, U> where U is not of type int.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.