SFINAE overload operator<< to call 'print' method if it exists - c++

I've been trying to understand SFINAE and was trying to write a simple overloaded operator << that would call the 'print' method on any class that contains such a method. I read through the answers on the question Is it possible to write a template to check for a function's existence? and tried writing:
template<class T, class = decltype(void(std::declval<T>().print), std::true_type{})>
inline std::ostream &operator<<(std::ostream &out, const T &obj) {
obj.print(out); return out; }
and
template<class T, class = decltype(void(std::declval<T>().print(std::declval<std::ostream &>())), std::true_type{})>
inline std::ostream &operator<<(std::ostream &out, const T &obj) {
obj.print(out); return out; }
but this simply doesn't work -- the compiler seems to have no problem instantiating the template for any type, so gives slews of 'ambiguous overload' errors when I try to print things like string literals...

Your "function exists" expression is incorrect. Try this:
template <typename T,
typename = decltype(
void(std::declval<T>().print(std::declval<std::ostream&>())),
std::true_type{})> // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
std::ostream & operator<<(std::ostream & out, const T & obj)
{
obj.print(out);
return out;
}
You might also consider this alternative:
template <typename T>
auto operator<<(std::ostream & out, const T & obj)
-> decltype(obj.print(out), (void)0, out)
{
obj.print(out);
return out;
}

I don't understand what you've meant your second type parameter
class = decltype(void(std::declval<T>().print), std::true_type{})
to mean. What is this supposed to evaluate to?
I think you can make it work by using the following.
#include <iostream>
#include <type_traits>
template<typename T,
typename = decltype(std::declval<const T>().print(std::cout))>
std::ostream&
operator<<(std::ostream& out, const T& obj)
{
obj.print(out);
return out;
}
struct A
{
void
print(std::ostream& out) const
{
out << "A";
}
};
int
main()
{
A a {};
std::cout << "And the winner is: " << a << std::endl;
}
It will correctly output And the winner is: A but there are probably some corner cases I've overlooked.
The expression
decltype(std::declval<const T>().print(std::cout))
will evaluate to the return type of the print(std::ostream&) const member function if such function is declared and a type error otherwise.

Related

Overloading ostream of vector template with iterator

Why I can't use iterator in ostream overloading?
If I use the same declaration using iterative approach it works.
Consider the following code:
template <class T>
class List {
template <class U>
friend ostream &operator<<(ostream &os, const List<U> &rhs);
private:
vector<T> v;
};
template<class U>
ostream & operator<<(ostream & os, const List<U>& rhs)
{
vector<U>::iterator it = rhs.v.begin();
return os;
}
int main()
{
List<int> list;
cout << list << endl;
return 0;
}
Note that rhs is declared as reference to const, then rhs.v will be const too, then rhs.v.begin() will return a std::vector<U>::const_iterator, which can't be converted to std::vector<U>::iterator directly.
You should use typename for dependent type names.
So change it to
typename vector<U>::const_iterator it = rhs.v.begin();
BTW: void main() should be int main().
Try with
typename vector<U>::const_iterator it = rhs.v.begin();
If your rsh is const, you should use a const_iterator

Check if an integer function [duplicate]

When I'm writing a function in a template class how can I find out what my T is?
e.g.
template <typename T>
ostream& operator << (ostream &out,Vector<T>& vec)
{
if (typename T == int)
}
How can I write the above if statement so it works?
Something like this:
template< class T >
struct TypeIsInt
{
static const bool value = false;
};
template<>
struct TypeIsInt< int >
{
static const bool value = true;
};
template <typename T>
ostream& operator << (ostream &out,Vector<T>& vec)
{
if (TypeIsInt< T >::value)
// ...
}
Since C++11 we have std::is_same:
if (std::is_same<T, int>::value) ...
It's implemented similar to the suggested trait TypeIsInt suggested in the other answers,
but with two types to be compared.
Define it explicitly, e.g.:
template <>
ostream& operator << (ostream &out,Vector<int>& vec)
{
}
Simplest, most general solution:
Just write a plain old overload of the function:
ostream& operator << (ostream &out,Vector<int>& vec)
{
// Your int-specific implementation goes here
}
This assumes that the int and non-int versions don't have much code in common, as you have to write two separate implementations.
IF you want to use one common implementation of the function, with just an if statement inside that differs, use Charles Bailey's implementation:
template< class T >
struct TypeIsInt
{
static const bool value = false;
};
template<>
struct TypeIsInt< int >
{
static const bool value = true;
};
template <typename T>
ostream& operator << (ostream &out,Vector<T>& vec)
{
if (TypeIsInt< T >::value) {
// your int-specific code here
}
}
In general, don't use typeid if you don't need to.
The easiest way is to provide a template specialisation:
#include <iostream>
#include <vector>
using namespace std;
template <typename T> struct A {
};
template <typename T >
ostream & operator <<( ostream & os, A<T> & a ) {
return os << "not an int" << endl;
}
template <>
ostream & operator <<( ostream & os, A<int> & a ) {
return os << "an int" << endl;
}
int main() {
A <double> ad;
cout << ad;
A <int> ai;
cout << ai;
}
This way.
ostream & operator << (ostream &out, Vector<int> const & vec)
{
// ...
}
The compiler will choose this function over the function template if you pass Vector<int>.
Edit: I found this article, which attempts to explain why to prefer overloading to template specialization.
TypeID is never a good idea. It relies on RTTI.
By the way here is your answer :http://www.parashift.com/c++-faq-lite/templates.html#faq-35.7
One more solution is:
if(std::is_same<T, int>::value)
//It is int
if (std::is_same<T, double>::value)
//It is double
if (std::is_same<T, long double>::value)
//It is long double
C++ templates don't work this way. The general idea of templates is express somethings which is common for a lot of different types. And in your case you should use template specialization.
template<class T> ostream& operator<< (ostream& out, const vector<T>& v)
{
// your general code for all type
}
// specialized template
template<> ostream& operator<< <int>(ostream& out, const vector<int>& vec)
{
// your specific to iny type code goes here
}
Then C++ compiler will call this function when you use int type and general implementation for any other type
std::vector<int> f(5, 5);
std::cout << f;

Can't use overloaded operator<< to print object's value

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?
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.

C++ containers - list members if operator<< is defined for type?

I am sorry if this is a duplicate, I'm not quite sure what I'm looking for.
I've defined a:
template<class T>
::std::ostream& operator<<(::std::ostream& stream,const container<T>& list);
which can just say "container of length" (or something)
and it'd be really nice if this could list the contents of the container, if
::std::ostream& operator<<(::std::ostream& stream, const T&);
was defined. It may not always be declared however. This is something that would be known at compile time (provided the compiler could see a declaration, user error could mean it is never included)
Can this be done?
This is most certainly a duplicate, I can't be the first to want to do this but I'm not sure what I'd be searching for.
Any means to do this would be appreciated.
Note:
I did think about using a trait but (to copy and paste my comment):
I
s there a C++11 way? I thought about traits too but you can't give
int a trait, assuming false by default (unless a trait exists and is
true) is great, but you can't do primitive types, or types defined
from libraries, you can of course create an operator<< for them
Example
Imagine:
container<int> someints(10); /*10 ints*/
container<A> someAs(5); /*5 As*/
container<B> someBs(7); /*7 Bs*/
With:
/*Obviously << for ints is defined*/
ostream& operator<<(ostream& stream, const B& b) {
stream<<"Whatever a B wants to do";
return stream;
}
template<class T>
ostream& operator<<(ostream& stream, const container<T>& list) {
stream<<"A list of length "<<list.get_length();
/*magic - if there is a << for T*/
stream<<"\n";
for(int k=0;k!=list.get_length();k++) {
stream<<list[k]<<"\n";
}
/*end of magic*/
return stream;
}
Then:
cout<<someints; /*shows a list of ints*/
cout<<someAs; /*shows its a list of 5 things - but cannot list the contents obviously*/
cout<<someBs; /*Showws it's a list of 7 things - and like someints lists them*/
This can be done: you'd use std::enable_if<...> to choose which version of the code should be used based on a predicate using the output operator. Below is a demonstration doing just that. The feature test is a bit ugly but right now I don't see how to really improve it. See here for a live example.
#include <iostream>
#include <type_traits>
template <typename T>
struct container
{
container(T const& v): value(v) {}
T value;
};
template <typename T>
struct has_output_test {
template <typename S>
static std::true_type test(typename std::decay<decltype(
std::declval<std::ostream&>() << std::declval<S>())>::type*);
template <typename S>
static std::false_type test(void*, ...);
};
template <typename T>
struct has_output
: decltype(has_output_test<T>::template test<T>(
static_cast<std::ostream*>(0)))
{
};
template <typename T>
typename std::enable_if<has_output<T>::value, std::ostream&>::type
operator << (std::ostream& out, container<T> const& c)
{
return out << "container[" << c.value << "]";
}
template <typename T>
typename std::enable_if<!has_output<T>::value, std::ostream&>::type
operator << (std::ostream& out, container<T> const&)
{
return out << "container[unknown]";
}
struct foo {};
int main()
{
std::cout << "foo=" << container<foo>(foo()) << '\n';
std::cout << "int=" << container<int>(int()) << '\n';
}
Yes. Boost has a type trait for that. More details at has_left_shift.
Here is an outline of how to do it:
template<typename T>
struct Container
{
void out(std::ostream& os, boost::true_type) const
{ os << "Huzzah"; }
void out(std::ostream& os, boost::false_type) const
{ os << "Oops"; }
friend std::ostream& operator<<(std::ostream& os, Container const& that)
{
using ostreamable = boost::has_left_shift<std::ostream, T>;
static_assert(ostreamable::value, "Not streamable");
that.out(os, ostreamable());
return os;
}
};
The static_assert will make it so you cannot stream out the container if T is not streamable; remove it if you want to do something else at run time for a non-streamable T.

how to query if(T==int) with template class

When I'm writing a function in a template class how can I find out what my T is?
e.g.
template <typename T>
ostream& operator << (ostream &out,Vector<T>& vec)
{
if (typename T == int)
}
How can I write the above if statement so it works?
Something like this:
template< class T >
struct TypeIsInt
{
static const bool value = false;
};
template<>
struct TypeIsInt< int >
{
static const bool value = true;
};
template <typename T>
ostream& operator << (ostream &out,Vector<T>& vec)
{
if (TypeIsInt< T >::value)
// ...
}
Since C++11 we have std::is_same:
if (std::is_same<T, int>::value) ...
It's implemented similar to the suggested trait TypeIsInt suggested in the other answers,
but with two types to be compared.
Define it explicitly, e.g.:
template <>
ostream& operator << (ostream &out,Vector<int>& vec)
{
}
Simplest, most general solution:
Just write a plain old overload of the function:
ostream& operator << (ostream &out,Vector<int>& vec)
{
// Your int-specific implementation goes here
}
This assumes that the int and non-int versions don't have much code in common, as you have to write two separate implementations.
IF you want to use one common implementation of the function, with just an if statement inside that differs, use Charles Bailey's implementation:
template< class T >
struct TypeIsInt
{
static const bool value = false;
};
template<>
struct TypeIsInt< int >
{
static const bool value = true;
};
template <typename T>
ostream& operator << (ostream &out,Vector<T>& vec)
{
if (TypeIsInt< T >::value) {
// your int-specific code here
}
}
In general, don't use typeid if you don't need to.
The easiest way is to provide a template specialisation:
#include <iostream>
#include <vector>
using namespace std;
template <typename T> struct A {
};
template <typename T >
ostream & operator <<( ostream & os, A<T> & a ) {
return os << "not an int" << endl;
}
template <>
ostream & operator <<( ostream & os, A<int> & a ) {
return os << "an int" << endl;
}
int main() {
A <double> ad;
cout << ad;
A <int> ai;
cout << ai;
}
This way.
ostream & operator << (ostream &out, Vector<int> const & vec)
{
// ...
}
The compiler will choose this function over the function template if you pass Vector<int>.
Edit: I found this article, which attempts to explain why to prefer overloading to template specialization.
TypeID is never a good idea. It relies on RTTI.
By the way here is your answer :http://www.parashift.com/c++-faq-lite/templates.html#faq-35.7
One more solution is:
if(std::is_same<T, int>::value)
//It is int
if (std::is_same<T, double>::value)
//It is double
if (std::is_same<T, long double>::value)
//It is long double
C++ templates don't work this way. The general idea of templates is express somethings which is common for a lot of different types. And in your case you should use template specialization.
template<class T> ostream& operator<< (ostream& out, const vector<T>& v)
{
// your general code for all type
}
// specialized template
template<> ostream& operator<< <int>(ostream& out, const vector<int>& vec)
{
// your specific to iny type code goes here
}
Then C++ compiler will call this function when you use int type and general implementation for any other type
std::vector<int> f(5, 5);
std::cout << f;