Reputation: 5616
I wrote tuple implementation, which seems to work:
template<typename T, typename... U>
struct tuple{
T first;
tuple<U...> second;
tuple()=default;
tuple(T t, U... u):first(t), second(u...){}
std::ostream& print(std::ostream& stream){
stream<<first<<", ";
return second.print(stream); //not using << to avoid extra () in output
}
};
template<typename T>
struct tuple<T>{
T first;
tuple()=default;
tuple(T t):first(t){}
operator T&(){
return first;
}
std::ostream& print(std::ostream& stream){
return stream<<first;
}
};
template<typename... T>
inline auto mk_tuple(T... t){
return tuple<T...>(t...);
}
I have operator<<
overloaded this way:
template<typename... T>
std::ostream& operator<<(std::ostream &stream, tuple<T...> &out){
stream<<'(';
return out.print(stream)<<')';
}
When I try to use it this way: std::cout<<mk_tuple(1, 2, 3, "xyz", 'c');
I get
error: cannot bind ‘std::ostream {aka std::basic_ostream<char>}’ lvalue to ‘std::basic_ostream<char>&&’
However, mk_tuple(1, 2, 3, "xyz", 'c').print(std::cout)
works.
(but it's unsatisfactory, because it's not obvious syntax in C++).
How should I overload operator<<
to be able to use it correctly in this case?
Upvotes: 2
Views: 474
Reputation: 56863
The signature is wrong, you need:
template<typename... T>
std::ostream& operator<<(std::ostream &stream, const tuple<T...> &out){
// ^^^^^
since you are not going to modify the tuple
on output. This then allows your operator to be called with constant or temporary values.
It also requires you to mark the print
method as const
:
std::ostream& print(std::ostream& stream) const {
// ^^^^^
Generally, google "const correctness" and learn about this essential paradigm in C++.
EDIT: Got it! Try this signature:
template<typename T, typename... U>
std::ostream& operator<<(std::ostream &stream, const tuple<T, U...> &out){
stream<<'(';
return out.print(stream)<<")";
}
as some older versions of GCC seem to have a bug that prevents them from properly deducing just T...
s.
Upvotes: 3