I have created a stream output operator for std::vector in my namespace, and I was able to use that in my previous debug code:
namespace my_company {
template <typename T>
std::ostream &operator<<(std::ostream &os, std::vector<T> const &vec) {
os << "{";
for (int i = 0; i < vec.size(); ++i) {
if (i != 0) {
os << ", ";
}
os << vec[i];
}
os << "}";
return os;
}
template <typename T>
void debug_impl(T const &var, char const *const expr, char const *const file, int const line) {
using std::vector;
std::lock_guard lg(debug_print_mutex);
std::cout << "DEBUG " << file << ":" << line << " T" << std::this_thread::get_id() << "\n " << expr << ": "
<< var << std::endl;}
#define DEBUG(var) ::my_company::debug_impl(var, #var, __FILE__, __LINE__)
}
But now I want to use my logger class:
namespace my_company {
class Logger {
public:
virtual ~Logger() = default;
virtual void log_impl(LogLevel log_level, std::string message) = 0;
template <typename... T>
void log_bits(LogLevel log_level, T const &...ts) {
if (log_level >= threshold)
log_impl(log_level, format_bits(ts...));
}
template <typename... T>
void trace(T const &...ts) {
log_bits(LogLevel::trace, ts...);
}
private:
LogLevel threshold = LogLevel::trace;
};
}
The format function is this one:
namespace my_company {
template <typename... T>
std::string format_bits(T const &...ts) {
std::ostringstream oss;
// The following is a C++17 [fold expression](https://en.cppreference.com/w/cpp/language/fold).
(oss << ... << ts);
return oss.str();
}
}
In the debug_impl function I just delegate to the logger now:
namespace my_company {
template <typename T>
void debug_impl(T const &var, char const *const expr, char const *const file, int const line) {
logger->template trace(file, ":", line, " T", std::this_thread::get_id(), "\n ", expr, ": ", var);
}
}
Clang doesn't like that:
logger.h:29:11: error: call to function 'operator<<' that is neither visible in the template definition nor found by argument-dependent lookup
(oss << ... << ts);
^
logger.h:44:27: note: in instantiation of function template specialization 'my_company::format_bits<const char *, char [2], int, char [3], std::thread::id, char [4], const char *, char [3], std::vector<bool, std::allocator<bool>>>' requested here
log_impl(log_level, format_bits(ts...));
^
logger.h:69:5: note: in instantiation of function template specialization 'my_company::Logger::log_bits<const char *, char [2], int, char [3], std::thread::id, char [4], const char *, char [3], std::vector<bool, std::allocator<bool>>>' requested here
log_bits(LogLevel::trace, ts...);
^
util.h:693:20: note: in instantiation of function template specialization 'my_company::Logger::trace<const char *, char [2], int, char [3], std::thread::id, char [4], const char *, char [3], std::vector<bool, std::allocator<bool>>>' requested here
logger->template trace(file, ":", line, " T", std::this_thread::get_id(), "\n ", expr, ": ", var);
^
rotating_buffer.h:40:5: note: in instantiation of function template specialization 'my_company::debug_impl<std::vector<bool, std::allocator<bool>>>' requested here
DEBUG(used);
^
util.h:699:42: note: expanded from macro 'DEBUG'
#define DEBUG(var) ::my_company::debug_impl(var, #var, __FILE__, __LINE__)
^
logger.h:13:15: note: 'operator<<' should be declared prior to the call site
std::ostream &operator<<(std::ostream &os, std::vector<T> const &vec) {
^
I have already declared that prior to the call site, it is all declared in the logger.h file, which is included by the others. The operator<< is the first thing in that file, so it should be available. I presume that the additional layer of templates did not make it any easier.
I have read a few other questions, but I don't understand how I can solve this issue as putting the operator<< into std isn't allowed, but it doesn't work in my_company and putting it into the global namespace doesn't work either. What can I do?
We use Clang 11 and C++20 on Linux.
Somewhat related:
Argument Dependent Lookup and stream operators overloading
Output stream operator Argument Dependent Lookup (ADL) for fundamental/STL types/classes
It seems to be a clang 11 bug.
Clang 12 accept the code Demo.
As work around, you might use, instead of (oss << ... << ts);:
((oss << ts), ...);
Related
In my experiments with scoped_allocator_adaptors using x86_64 gcc/clang trunk, I've run into an issue where the code snippet below compiles if the extended copy constructor is enabled but without it results is_constructible static assertion below. The compiler complains of the extended copy constructor not being defined even though it is never invoked when enabled. Can someone help answer why that might be the case?
#include <iostream>
#include <vector>
#include <scoped_allocator>
template <typename T>
struct MyAlloc
{
using value_type = T;
MyAlloc(const std::string &scope) noexcept : _scope(scope) {}
// Rebinding allocatos to different type
template <class U> MyAlloc(MyAlloc<U> const& other) noexcept : _scope(other._scope) {}
value_type* allocate(std::size_t n) noexcept
{
std::cout << "Allocating " << n << " objects within " << _scope << " from " << __PRETTY_FUNCTION__ << std::endl;
return static_cast<value_type*>(::operator new (n*sizeof(value_type)));
}
void deallocate(value_type* p, std::size_t n) noexcept
{
std::cout << "Deallocating " << n << " objects within " << _scope << " from " << __PRETTY_FUNCTION__ << std::endl;
::operator delete(p);
}
std::string _scope;
};
template <typename T>
using MyAllocAdaptor = std::scoped_allocator_adaptor<MyAlloc<T>>;
template <typename T> // adaptor to propagate
using myvec = std::vector<T, MyAllocAdaptor<T>>;
template <typename T>
using bstr = std::basic_string<T, std::char_traits<T>, MyAlloc<T>>;
using mystring = bstr<char>;
// Example struct with multiple nested containers with different types
// More realistic example that single type containers
class S
{
int z;
mystring str;
myvec<int> vec;
public:
// If not public, the allocator aware constructor is not invoked
// limiting the propagation of the allocator
using allocator_type = MyAllocAdaptor<S>;
S(allocator_type alloc) :
z(1),
str("This string should really not have SBO....", std::allocator_traits<allocator_type>::rebind_alloc<char>(alloc)),
vec(std::allocator_traits<allocator_type>::rebind_alloc<int>(alloc))
{
vec.push_back(10);
}
S() : S(allocator_type("NoScope")) {
std::cout << "Should not be invoked " << __PRETTY_FUNCTION__ << std::endl;
}
~S()
{
std::cout << __PRETTY_FUNCTION__ << " Z " << z << std::endl;
}
#if 0 // If this is defined things compile
S(const S& other, allocator_type alloc = {}) :
str(other.str, std::allocator_traits<allocator_type>::rebind_alloc<char>(alloc)),
vec(other.vec, std::allocator_traits<allocator_type>::rebind_alloc<int>(alloc))
{
}
#endif
};
int main()
{
MyAlloc<S> alloc("scope1");
myvec<S> vec(alloc);
vec.emplace_back();
}
Compiler error when the extended copy constructor is not defined (even though it's never invoked when defined)
In file included from <source>:3:
In file included from /opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/11.0.0/../../../../include/c++/11.0.0/scoped_allocator:39:
In file included from /opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/11.0.0/../../../../include/c++/11.0.0/tuple:40:
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/uses_allocator.h:96:7: error: static_assert failed due to requirement '__or_<std::is_constructible<S, std::allocator_arg_t, const std::scoped_allocator_adaptor<MyAlloc<S>> &, const S &>, std::is_constructible<S, const S &, const std::scoped_allocator_adaptor<MyAlloc<S>> &>>::value' "construction with an allocator must be possible if uses_allocator is true"
static_assert(__or_<
^ ~~~~~~
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/11.0.0/../../../../include/c++/11.0.0/scoped_allocator:377:8: note: in instantiation of template class 'std::__uses_alloc<true, S, std::scoped_allocator_adaptor<MyAlloc<S>>, const S &>' requested here
= std::__use_alloc<_Tp, inner_allocator_type, _Args...>(__inner);
^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/alloc_traits.h:247:8: note: in instantiation of function template specialization 'std::scoped_allocator_adaptor<MyAlloc<S>>::construct<S, const S &>' requested here
{ __a.construct(__p, std::forward<_Args>(__args)...); }
^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/stl_uninitialized.h:318:16: note: in instantiation of function template specialization 'std::allocator_traits<std::scoped_allocator_adaptor<MyAlloc<S>>>::construct<S, const S &>' requested here
__traits::construct(__alloc, std::__addressof(*__cur), *__first);
^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/stl_uninitialized.h:353:19: note: in instantiation of function template specialization 'std::__uninitialized_copy_a<const S *, S *, std::scoped_allocator_adaptor<MyAlloc<S>>>' requested here
return std::__uninitialized_copy_a
^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/vector.tcc:473:10: note: in instantiation of function template specialization 'std::__uninitialized_move_if_noexcept_a<S *, S *, std::scoped_allocator_adaptor<MyAlloc<S>>>' requested here
= std::__uninitialized_move_if_noexcept_a
^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/vector.tcc:121:4: note: in instantiation of function template specialization 'std::vector<S, std::scoped_allocator_adaptor<MyAlloc<S>>>::_M_realloc_insert<>' requested here
_M_realloc_insert(end(), std::forward<_Args>(__args)...);
^
<source>:78:9: note: in instantiation of function template specialization 'std::vector<S, std::scoped_allocator_adaptor<MyAlloc<S>>>::emplace_back<>' requested here
vec.emplace_back();
^
1 error generated.
Compiler returned: 1
running through the following function using gdb in vscode tells me that the deduced argTypes for a function of the form T (*)(const int &, const int *, int &, int) are int const int * int & and int respectively. Is there any way to force the compiler to deduce const Type & when presented with a const Type & argument? Or is there some other means by which I can extract that type information in a useful way?
#include<typeinfo>
template<typename T, typename...argTypes>
void testfunc(T (*f)(argTypes...))
{
const char *a[] = { typeid(argTypes).name()... };
for(auto &av :a)
{
std::cout << av << std::endl;
}
}
edit:
A little more context: this function obviously does little to nothing, but the problem function that spawned it also takes in all the arguments to be run with f in a way that they are not deduced, but converted.
This presents a problem for non-copyable objects to be used as const references.
An example of using testfunc is as follows:
#include "testfunc.h"
std::vector<bool> funcToTest(const int &a, const int *b, int &c, int d)
{
std::vector<bool> out;
out.push_back(&a == b);
out.push_back(&c == b);
out.push_back(&d == b);
return out;
}
int main()
{
// put a breakpoint here, and step in, you would see that 'a'
// describes the situation as described above.
testfunc(funcToTest);
}
The issue here is with typeid, not template deduction. If you use
template<typename... Ts>
struct types;
template<typename T, typename...argTypes>
void testfunc(T (*f)(argTypes...))
{
types<argTypes...>{};
}
You get an nice error message like
main.cpp: In instantiation of 'void testfunc(T (*)(argTypes ...)) [with T = std::vector<bool>; argTypes = {const int&, const int*, int&, int}]':
main.cpp:30:24: required from here
main.cpp:12:5: error: invalid use of incomplete type 'struct types<const int&, const int*, int&, int>'
12 | types<argTypes...>{};
| ^~~~~
main.cpp:7:8: note: declaration of 'struct types<const int&, const int*, int&, int>'
7 | struct types;
| ^~~~~
which shows you that the function parameter types are correctly deduced.
With typeid if the type is a reference, then it returns the referred to type. It also drops all cv-qualifactions on the types. That means
int main()
{
std::cout << typeid(int).name() << "\n";
std::cout << typeid(int&).name() << "\n";
std::cout << typeid(const int).name() << "\n";
std::cout << typeid(const int&).name() << "\n";
std::cout << typeid(volatile int).name() << "\n";
std::cout << typeid(volatile int&).name() << "\n";
std::cout << typeid(const volatile int).name() << "\n";
std::cout << typeid(const volatile int&).name() << "\n";
}
prints
i
i
i
i
i
i
i
i
Section 16.3 of C++ Primer (5th edition) - Overloading and Templates -, teaches the function matching procedure in the presence of candidate function template(s) instantiations.
Here are the declaration for the function templates used in this section:
using std::string;
template <class T> string debug_rep(const T &); /* 1 */
template <class T> string debug_rep(T *); /* 2 */
// definitions not relevant for the questions
First example
string s("SO");
debug_rep(&s);
it is then said that the generated instantiations will thus be:
debug_rep(const string *&) (with T bound to string *)
debug_rep(string *)
Q1 Is it correct for #1 ? Should not it instantiate debug_rep(string* const &) instead?
Second example
const string *sp = &s;
debug_rep(sp); //string literal type is const char[10]
it is then said that the generated instantiations will thus be:
debug_rep(const string *&) (with T bound to const string *)
debug_rep(const string *)
Thus, both instantiated candidate would provide an exact match, selection being made on the more specialized template (-> #2)
Q2.1 Is it correct for #1 ? Should not it instantiate debug_rep(const string* const &)?
Q2.2 Assuming the instantiated function is the one just above, can we affirm it is not an exact match any more ?
Third example
debug_rep("SO world!"); //string literal type is const char[10]
it is then said that the generated instantiations will thus be:
debug_rep(const T &) (with T bound to char[10])
debug_rep(const string *)
Thus, both instantiated candidate would provide an exact match, selection being made on the more specialized template (-> #2)
Q3.1 Is the type deduced for T correct in #1 ? Should not it be const char[10] instead ?
Q3.2 Assuming the deduced type for T is actually the one just above, can we affirm it is not an exact match any more ?
You're given these declarations:
using std::string;
template <class T> string debug_rep(const T &); /* 1 */
template <class T> string debug_rep(T *); /* 2 */
In the invocation
string s("SO");
debug_rep(&s);
the &s produces a string*, which can only match the T const& of (1) when T is string*. For the T* in (2), there is a match for T bound to string. So, provided your quoting is correct, the book is wrong about
debug_rep(const string *&)
being a possible instantiation: there is no such.
The instantiation resulting from T = string* would instead be
debug_rep( string* const& )
But which instantiation will be called?
As a general rule the simplest match is superior, but I never manage to remember the exact rules, so, I ask Visual C++ (because its typeid(T).name() produces readable type names by default):
#include <iostream>
#include <string>
#include <typeinfo>
using namespace std;
template< class T >
struct Type {};
template <class T> auto debug_rep( T const& ) // 1
-> string
{ return string() + "1 --> T = " + typeid(Type<T>).name(); }
template <class T> auto debug_rep( T* ) // 2
-> string
{ return string() + "2 --> T = " + typeid(Type<T>).name(); }
auto main() -> int
{
string s( "SO" );
cout << debug_rep( &s ) << endl;
cout << "The type 'int const' is shown as " << typeid(Type<int const>).name() << endl;
}
And it says:
2 --> T = struct Type<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >
The type 'int const' is shown as struct Type<int const >
And so on for your second and third examples: apparently the author got some mixup regarding const.
EDIT: Thanks to Alf answer, and its elegant trick to conserve complete information about a type while using typeid, I was able to write a program that addresses most of my questions (changing from std::string to int for output readability.)
The complete code can be edited and run rextester online IDE.
Let's define a few classes and methods:
template <class> class Type{}; // Allowing to get full type information with typeid
template <class T> std::string typeStr()
{ return typeid(Type<T>).name(); }
template <class T> void debug_rep(const T &a) /* 1 */
{
std::cout << "[1] T type is: " << typeStr<T>()
<< "\t| arg type is: " << typeStr<decltype(a)>() << std::endl;
}
template <class T> void force_1(const T &a) /* 1 */
{
std::cout << "[forced 1] T type is: " << typeStr<T>()
<< "\t| arg type is: " << typeStr<decltype(a)>() << std::endl;
}
template <class T> void debug_rep(T *a) /* 2 */
{
std::cout << "[2] T type is: " << typeStr<T>()
<< "\t| arg type is: " << typeStr<decltype(a)>() << std::endl;
}
example 1
Running:
std::cout << "---First example---" << std::endl;
int i = 41;
debug_rep(&i);
force_1(&i);
Displays:
---First example---
[2] T type is: class Type<int> | arg type is: class Type<int *>
[forced 1] T type is: class Type<int *> | arg type is: class Type<int * const &>
Q1: we can remark that, when we call force_1, instantiating a template corresponding to #1, the argument type is int * const &, so the book is not correct, and the instantiated candidate #1 would be
debug_rep(int* const &)
example 2
Running:
std::cout << "---Second example---" << std::endl;
const int *ip = &i;
debug_rep(ip);
force_1(ip);
Displays:
---Second example---
[2] T type is: class Type<int const > | arg type is: class Type<int const *>
[forced 1] T type is: class Type<int const *> | arg type is: class Type<int const * const &>
Q2.1: Calling force_1, we remark that the argument type will be int const * const &, so the book is missing const qualification on the reference. The instantiated candidate will actually be:
debug_rep(const int * const &)
Q2.2 The second candidate being debug_rep(const int *), it is an exact match for ip (which is a pointer to constant integer). To check if the first candidate has a lower rank, let's write:
void debug_rep_plain_b(const int * const &) /* 1 */
{ std::cout << "[plain 1]" << std::endl;}
void debug_rep_plain_b(const int *) /* 2 */
{ std::cout << "[plain 2]" << std::endl; }
If we try to compile:
debug_rep_plain_b(ip)
There is a compilation error for ambiguous call: So the answer to Q2.2 is NO, it is still an exact match ! For the templated version, the compiler actually uses the rule regarding the most specialized template to resolve the ambiguity.
Even if there is a mistake in the deduced candidate, the book is correct regarding the fact that this example illustrates overload resolution using the most specialized template.
example 3
Running:
std::cout << "---Third example---" << std::endl;
const int ia[3] = {1, 2, 3};
debug_rep(ia);
force_1(ia);
Displays:
---Third example---
[2] T type is: class Type<int const > | arg type is: class Type<int const *>
[forced 1] T type is: class Type<int const [3]> | arg type is: class Type<int const (&)[3]>
Q3.1 The type deduced for T by CL is array of const integer, so the book would be mistaken.
BUT the result is inconsistent with GCC or Clang, that would output:
---Third example---
[2] T type is:4TypeIKiE | arg type is: 4TypeIPKiE
[forced 1] T type is:4TypeIA3_iE | arg type is: 4TypeIRA3_KiE
The interesting part being:
[forced 1] T type is:4TypeIA3_iE
meaning that they deduce T as an array of 3 non-const integers (because _i, not _Ki), which would agree with the book.
I will have to open another question for this one, I cannot understand the type deduction operated by GCC and Clang...
I am trying to overload the << operator on a class in C++. Whenever I insert a normal string, like the " " into the output stream I get compilation errors that I cannot make sense of. I have done this once before with no problems, so I am very confused.
friend std::ostream& operator<<(std::ostream& out, Variable v);
std::ostream& operator<<(std::ostream& out, Variable v) {
out << v.type;
out << " ";
out << v.name;
return out;
}
And here is the output:
src/Variable.cpp: In function 'std::ostream& operator<<(std::ostream&, Variable)':
src/Variable.cpp:35:9: error: no match for 'operator<<' in 'out << " "'
src/Variable.cpp:35:9: note: candidates are:
src/Variable.cpp:33:15: note: std::ostream& operator<<(std::ostream&, Variable)
src/Variable.cpp:33:15: note: no known conversion for argument 2 from 'const char [2]' to 'Variable'
In file included from /usr/local/Cellar/gcc/4.7.0/gcc/lib/gcc/x86_64-apple-darwin10.8.0/4.7.0/../../../../include/c++/4.7.0/string:54:0,
from src/../inc/Variable.h:4,
from src/Variable.cpp:1:
/usr/local/Cellar/gcc/4.7.0/gcc/lib/gcc/x86_64-apple-darwin10.8.0/4.7.0/../../../../include/c++/4.7.0/bits/basic_string.h:2750:5: note: template<class _CharT, class _Traits, class _Alloc> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::basic_string<_CharT, _Traits, _Alloc>&)
/usr/local/Cellar/gcc/4.7.0/gcc/lib/gcc/x86_64-apple-darwin10.8.0/4.7.0/../../../../include/c++/4.7.0/bits/basic_string.h:2750:5: note: template argument deduction/substitution failed:
src/Variable.cpp:35:9: note: mismatched types 'const std::basic_string<_CharT, _Traits, _Alloc>' and 'const char [2]'
make: *** [bin/Variable.o] Error 1
Derp. I did not include iostream. However, this does not make much sense to me... since it worked whenever I did not add a string to the ostream. I would think that the compiler would not be able to find ostream at all, and would complain about that
#include <utility>
#include <iostream>
template <typename T1, typename T2>
std::ostream& operator<< (std::ostream& out, const std::pair<T1, T2>& v)
{
out << v.first;
out << " ";
out << v.second << std::endl;
return out;
}
int main()
{
std::pair<int, int> a = std::make_pair(12, 124);
std::cout << a << std::endl;
return EXIT_SUCCESS;
}
Its an example how to declare and implement an operator <<
I will show your solution in code
#include <iostream>
#include <string>
/* our custom class */
class Developer
{
public:
Developer(const std::string& name, int age) :
m_name(name),
m_age(age)
{}
const std::string& name() const { return m_name; }
int age() const { return m_age; }
private:
std::string m_name;
int m_age;
};
/* overloaded operator<< for output of custom class Developer */
std::ostream& operator<< (std::ostream& stream, const Developer& developer)
{
stream << "Developer name:\t" << developer.name() << std::endl;
stream << "Developer age:\t" << developer.age() << std::endl;
return stream;
}
/* test custom operator<< for class Developer */
int main(int argc, const char** argv)
{
Developer max("Maxim", 23);
std::cout << max;
return 0;
}
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.).
Does anyone know why gcc can't automatically bind this?
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.
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.
You can call operator<< with specified template parameters in this, not so aestethic, way:
operator<< <double,2>(std::cout, lower) << std::endl;