I want to be able to << val.first() and val.second() element in
struct Data<std::pair<F, S>. F, S should be generic in the sense that they can be anything specified like struct Data<int> (specific type). I don't know how to write the template for struct Data<std::pair<F, S> in a way that allows it to only take struct Data as F or S.
#include <fstream>
#include <iostream>
#include <sstream>
#include <utility>
template <typename T>
struct Data;
template <typename T>
std::ostream& operator<<(std::ostream& os, const Data<T>& val) {
return val(os);
}
template <typename T>
Data<std::remove_cv_t<T>> data(const T& val) { return { val }; }
template <>
struct Data<int> {
std::ostream& operator()(std::ostream& os) const {
os << val;
return os;
}
const int& val;
};
//More struct Data for templatized types for other specific types
template <typename F, typename S>
struct Data<std::pair<F, S> > {
std::ostream& operator()(std::ostream& os) const {
os << data(val.first()) << data(val.second());
return os;
}
std::pair<F, S> val;
};
//More struct Data templatized for other container types
The error when tested is:
error: called object type 'int' is not a function or function pointer
os << data(val.first()) << data(val.second());
^~~~~~~~~
first and second are two (public) member variables of std::pair, they are not member functions.
os << data(val.first()) << data(val.second());
becomes
os << data(val.first) << data(val.second);
Related
I saw this example of using SFINAE to check if a type is streamable here. However, I noticed that it is not portable, i.e. returns different results for templated types with different compilers. I'd be glad for any tips to understand the problem here.
The code below returns true, false with any version of clang++ and GCC 12 or higher, but true, true with earlier versions of GCC.
You can try it online here.
#include <iostream>
#include <type_traits>
#include <vector>
template <typename T, typename dummy = void>
struct is_printable : std::false_type {};
template <typename T>
struct is_printable<
T, typename std::enable_if_t<std::is_same_v<
std::remove_reference_t<decltype(std::cout << std::declval<T>())>,
std::ostream>>> : std::true_type {};
template <typename T>
inline constexpr bool is_printable_v = is_printable<T>::value;
struct C {};
std::ostream& operator<<(std::ostream& os, const C& c) {
os << "C";
return os;
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& v) {
for (const auto& el : v) {
os << el;
}
return os;
}
int main(int argc, const char* argv[]) {
std::cout << std::boolalpha;
std::cout << is_printable_v<C> << std::endl;
std::cout << is_printable_v<std::vector<int>> << std::endl;
return 0;
}
operator<<(std::ostream& os, const std::vector<T>& v) won't be found by ADL (for std::vector<int>, it would for std::vector<C>) (and so need to be declared before usage to be usable).
That is why correct answer is true, false.
previous version of gcc misbehave on this.
Note: It is discouraged to overload operator for types which you don't own. std might in the future add that overload, and you will have ODR (One definition rule) violation. Same if another library does the same wrong thing than you.
Adding a forwarding declaration help:
template <typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& v);
Full code:
#include <iostream>
#include <type_traits>
#include <vector>
template <typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& v);
template <typename T, typename dummy = void>
struct is_printable : std::false_type {};
template <typename T>
struct is_printable<
T, typename std::enable_if_t<std::is_same_v<
std::remove_reference_t<decltype(std::cout << std::declval<T>())>,
std::ostream>>> : std::true_type {};
template <typename T>
inline constexpr bool is_printable_v = is_printable<T>::value;
struct C {};
std::ostream& operator<<(std::ostream& os, const C& c) {
os << "C";
return os;
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& v) {
for (const auto& el : v) {
os << el;
}
return os;
}
int main(int argc, const char* argv[]) {
std::cout << std::boolalpha;
std::cout << is_printable_v<C> << std::endl;
std::cout << is_printable_v<std::vector<int>> << std::endl;
return 0;
}
Demo : https://godbolt.org/z/qKz537TPr
I know I didn't answer "why both version behave differently" but I think it may help :)
I want to do something like this:
#include <iostream>
template<typename T>
class myclass
{
T something;
public:
myclass(T something) : something{ something }
{ }
struct result
{
T value;
};
result get_result()
{
return{ something };
}
};
template<typename T>
std::ostream& operator<<(std::ostream& stream, const typename myclass<T>::result& res)
{
return stream << res.value;
}
int main()
{
myclass<int> m(0);
std::cout << m.get_result() << "\n";
}
In this case neither gcc nor msvc find the overloaded stream operator when I put in a result (which is dependent on a templated outer class). Is what I am trying to do even possible?
T is non-deductible for myclass<T>::result.
You may define operator<< inside the class to solve your issue:
struct result
{
T value;
friend std::ostream& operator<<(std::ostream& stream, const result& res)
{
return stream << res.value;
}
};
Demo
I have this snippet of code and I do not understand why the std::cout line is not compiling... The argument lookup / template argument inferencing seems correct...
#include <iostream>
template<typename T>
struct A
{
struct M1
{
T x;
};
};
template<typename T>
std::ostream &operator<<(std::ostream &os, typename A<T>::M1 const &o)
{
os << o.x;
return os;
}
int main()
{
A<int>::M1 a;
std::cout << a; // This line fails
return 0;
}
BTW I'm trying to do this without a declaring operator<<() as an inline function.
Your problem is that T is in a non deduced context. C++ will only simple pattern match, it will not invert possibly arbitrary type maps.
Imagine there was a specialization of A<void> that set using M1=A<int>::M1. Now both int and void are valid T for your <<. As the problem is intractible in general, C++ refuses to even try: you can only pattern match on direct template arguments of your argument types.
To do what you really want:
template<typename T>
struct A {
struct M1 {
T x;
friend std::ostream& operator<<(std::ostream& os, M1 const& m1){
return os << m1.x;
}
};
};
Learn to love Koenig operators.
The template parameter T of your operator cannot be deduced. However, there is some workaround using some SFINAE magic:
#include <iostream>
template<typename T>
struct A {
struct M1 {
using type = T;
T x;
};
};
template<typename T, std::enable_if_t<std::is_same<T, typename A<typename T::type>::M1>::value, int> = 0>
std::ostream &operator<<(std::ostream &os, const T& o)
{
os << o.x;
return os;
}
int main()
{
A<int>::M1 a;
std::cout << a; // This line works
return 0;
}
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.
I want to print state of my objects through toString member function, but I want to call it through String::toString(var). But I want to do this only for object, who doesn't have operator<< defined.
My attempt is below.
I have template operator<< which call toString, but I hoped that this operator will be taken into account only if no other suitable operator<< has been found. I was obviously wrong :)
#include <iostream>
#include <sstream>
struct WithToString
{
std::string toString()
{ return std::string ("foo") ; }
};
struct WithoutToString {};
struct String
{
template <typename T>
static std::string toString(T & var)
{
std::stringstream s;
s << var;
return s.str();
}
};
template <typename T>
std::ostream & operator<<(std::ostream & s, T & var)
{
s << var.toString();
return s;
}
int main(int argc, char *argv[])
{
int i = 5;
std::cout << String::toString(i); //fine, prints 5
WithToString w;
std::cout << String::toString(w); //fine, prints foo
// WithoutToString ws;
// std::cout << String::toString(ws); //fine - give "toString is not a member" error
// const char * s = "bar";
// std::cout << String::toString(s); //error - operator << is ambiguous
// std::string s = "bar";
// std::cout << String::toString(s); //error - toString is not a member
return 0;
}
How to achieve this behavior?
EDIT
here is my other attempt, but again fails with string and char *
template <class Type, class V>
class HasOperatorShiftLeft
{
template <typename T, T> struct TypeCheck;
typedef char Yes;
typedef long No;
template <typename T> struct ToString
{
typedef std::ostream & (T::*fptr)(V);
};
template <typename T> static Yes HasOpShift(TypeCheck< typename ToString<T>::fptr, &T::operator<< >*);
template <typename T> static No HasOpShift(...);
public:
static bool const value = (sizeof(HasOpShift<Type>(0)) == sizeof(Yes));
};
template <typename T, int A>
struct toStringStr{};
template <typename T>
struct toStringStr<T,1>
{
static std::string toString(T & var)
{
std::stringstream s;
s << var;
return s.str();
}
};
template <typename T>
struct toStringStr<T,0>
{
static std::string toString(T & var)
{
return var.toString();
}
};
template <typename T>
std::string toString(T & var)
{
return toStringStr<T,HasOperatorShiftLeft<std::ostream,T>::value>::toString(var);
}
EDIT
my newest attempt is posted as Answer, because I think, it works
This is actually pretty easy, albeit stupid to do as described in the comments. With C++11:
template<class T>
auto operator<<(std::ostream& os, T const& val)
-> decltype(os << val.toString())
{
return os << val.toString();
}
This function will only exist if what's inside decltype(..) is a valid expression. Now just stream everything into an std::ostream& and call it a day. If a type has both toString and and overloaded operator<< for std::ostream&, well, tough. You'll get an "ambiguous call to overloaded operator<<" error.
For C++03, there's another option. Since you seem to kinda dislike free functions, I'll assume you like interfaces. As such, get yourself a Streamable base class with a virtual std::string toString() const = 0 method and overload operator<< only for that. Presto, you have operator<< for all classes that implement that interface!
struct Streamable{
virtual std::string toString() const = 0;
};
std::ostream& operator<<(std::ostream& os, Streamable const& s){
return os << s.toString();
}
Or you can even go down to the meta level to get rid of the useless virtual function call:
template<class D>
struct Streamable{
std::string toString() const{
return static_cast<D const&>(*this).toString();
}
};
template<class D>
std::ostream& operator<<(std::ostream& os, Streamable<D> const& s){
return os << s.toString();
}
// example:
struct Blub
: public Streamable<Blub>
{
// implement toString() ...
};
What about this?
I think it works just fine...
struct String
{
template <typename T>
static std::string toString(const T & var)
{
std::stringstream s;
s << var;
return s.str();
}
};
template<typename Elem, typename Traits, typename T>
std::basic_ostream<Elem, Traits> & operator <<(std::basic_ostream<Elem, Traits> & s, const T & var)
{
s << var.toString();
return s;
}