I have a non type class template (e.g. Counted) that points to an instance of a class template (e.g. Counter). Everything works fine as long as both template classes are siblings, for example writing a print operator.
Now for several reasons, I want to move Counted inside of Counter as an inner class, and I find myself unable to write a printing operator.
Here's a working "sibling class" version, with the main code here:
template < class Count >
struct Counter {
using count_type = Count;
count_type instances = 0;
};
template < class Cnt, Cnt& c>
struct Counted {
using id_type = typename Cnt::count_type;
id_type id;
Counted() : id(c.instances) { ++c.instances; }
~Counted() { --c.instances; }
};
template < class Cnt, Cnt& c >
std::ostream& operator<<(std::ostream& os, Counted<Cnt,c> sib) {
os << "printing sibling " << sib.id;
return os;
}
using SCounter = Counter<std::size_t>;
SCounter sc;
using SCounted = Counted<SCounter, sc>;
Here's the not compiling "inner class" version with the main code here :
template < class Count >
struct Counter {
using count_type = Count;
count_type instances = 0;
template <Counter& c>
struct Counted {
using id_type = count_type;
id_type id;
Counted() : id(c.instances) { ++c.instances; }
~Counted() { --c.instances; }
};
};
template < class Count, Counter<Count>& c >
std::ostream& operator<<(std::ostream& os,
typename Counter<Count>::template Counted<c>& sib) {
os << "printing inner " << sib.id;
return os;
}
using SCounter = Counter<std::size_t>;
SCounter sc;
using SCounted = SCounter::Counted<sc>;
Errors:
prog.cpp: In function 'int main()':
prog.cpp:32:15: error: cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'
std::cout << j << std::endl;
^
In file included from /usr/include/c++/4.9/iostream:39:0,
from prog.cpp:1:
/usr/include/c++/4.9/ostream:602:5: note: 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<char>; _Tp = Counter<unsigned int>::Counted<(* & sc)>]'
operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
^
Is there a problem in my code, in my compiler, or is this simply not allowed by the standard ?
Koenig operators are what you want:
template <Counter& c>
struct Counted {
using id_type = count_type;
id_type id;
Counted() : id(c.instances) { ++c.instances; }
~Counted() { --c.instances; }
friend std::ostream& operator<<(
std::ostream& os,
Counted const& sib
) {
os << "printing inner " << sib.id;
return os;
}
};
};
here we create a friend operator<<. It will be found via ADL (or Koenig lookup) when you try to use << with a Counted instance.
A different function is created, and no template deduction is done, for each type of Counted.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With