10

The following code gives a compiler error (gcc-4.7 run with -std=c++11):

#include <iostream>
#include <array>

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

int main() {
  std::array<double, 2> lower{1.0, 1.0};
  std::cout << lower << std::endl;
  return 0;
}

Error message:

tmp6.cpp: In function ‘int main()’: tmp6.cpp:16:16: error: cannot bind
‘std::ostream {aka std::basic_ostream}’ lvalue to
‘std::basic_ostream&&’ In file included from
/usr/include/c++/4.7/iostream:40:0,
from tmp6.cpp:1: /usr/include/c++/4.7/ostream:600:5: error: initializing argument 1 of ‘std::basic_ostream<_CharT,
_Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits; _Tp = std::array]’

When I get rid of the template function declaration and replace T with double and N with 2, it compiles just fine (edit: leaving T and replacing N with 2 works, but specifying N=2 as the default argument for N doesn't work.).

  1. Does anyone know why gcc can't automatically bind this?
  2. What would be the syntax for calling the << operator with explicitly specified template parameters?

Answer to question 2: operator<<<double, 2>(std::cout, lower);

Edit: This is also true for the following function, which is only templated in the array size:

template <int N>
void print(const std::array<double, N> & arr) {
  std::cout << "print array here" << std::endl;
}

int main() {
  std::array<double, 2> lower{1.0, 1.0};
  print<2>(lower); // this works
  print(lower);    // this does NOT work
  return 0;
}

Thanks a lot for your help.

ildjarn
  • 62,044
  • 9
  • 127
  • 211
user
  • 7,123
  • 7
  • 48
  • 90
  • 1
    Note that you shouldn't be defining `operator <<` for a standard type. – K-ballo Jun 02 '12 at 22:47
  • @K-ballo Any idea how to answer either of the two numbered questions in the post? – user Jun 02 '12 at 22:48
  • If I could answer, I would have placed an answer instead of a comment... The problem probably comes from implementing operators in a wrong way. – K-ballo Jun 02 '12 at 22:50
  • @K-ballo The same question could be proposed using a function `template print (const std::array & arr) { /*...*/ }`. I wonder why gcc can't bind this... – user Jun 02 '12 at 23:05
  • Do you mean `print( lower );` won't compile? Could you add your test case for the `print` version to your question? – K-ballo Jun 02 '12 at 23:06
  • also see http://stackoverflow.com/a/645273/34509 – Johannes Schaub - litb Jun 03 '12 at 10:31

2 Answers2

13

Consider your declaration:

template <typename T, int N>
std::ostream & operator <<(std::ostream & os, const std::array<T, N> & arr) {

The definition for std::array is:

template<typename T, std::size_t N> class array {...};

You are using int instead of std::size_t, and that's why it doesn't match.

K-ballo
  • 80,396
  • 20
  • 159
  • 169
  • Huge +1. Thanks a lot, I'm not sure I *ever* would have found that. – user Jun 02 '12 at 23:10
  • +1 I was just reading what standard (14.8.2) says about template deduction and wondered what I've omitted, because there was nothing against this kind of deduction. The incorrect type in the template definition catched me too. – Rafał Rawicki Jun 02 '12 at 23:14
1

You can call operator<< with specified template parameters in this, not so aestethic, way:

operator<< <double,2>(std::cout, lower) << std::endl;
Rafał Rawicki
  • 22,324
  • 5
  • 59
  • 79
  • +1 I don't know why I didn't just try that-- I was so hung up on the `<<<` that I didn't think the compiler would like it (I guess I was projecting)! – user Jun 02 '12 at 22:58