How to select correct operator overload - c++

I have this data and operator defined in namespace a:
namespace a {
enum class E {
VALUE
};
std::ostream& operator<<(std::ostream& os, const E e)
{
return os << "VALUE";
}
}
My code operates in namespace b, and it would like to use another operator<< for the same type, replacing the one originally defined in namespace a:
namespace b {
std::ostream& operator<<(std::ostream& os, const a::E e)
{
return os << "value";
}
void f()
{
const auto e = a::E::VALUE;
std::cout << e << std::endl;
}
}
int main()
{
b::f();
return 0;
}
Because of ADL, compiler get confused and sees the call to operator<< as an ambiguous call, since both the namespace a and namespace b version are available.
How can I make it use my version of operator<< when user code is inside namespace b without ambiguity?

Another way:
namespace b {
template<class T>
struct Wrapper { T value; };
template<class T>
inline Wrapper<T> wrap(T t) {
return {t};
}
std::ostream& operator<<(std::ostream& os, Wrapper<a::E> e) {
return os << "value";
}
void f() {
const auto e = a::E::VALUE;
std::cout << wrap(e) << std::endl;
}
} // namespace b
Alternatively, with reusable Wrapper:
template<class Tag, class T>
struct Wrapper { T value; };
template<class Tag, class T>
inline Wrapper<Tag, T> wrap(T t) {
return Wrapper<Tag, T>{t};
}
namespace b {
struct Tag {};
std::ostream& operator<<(std::ostream& os, Wrapper<Tag, a::E> e) {
return os << "value";
}
void f() {
const auto e = a::E::VALUE;
std::cout << wrap<Tag>(e) << std::endl;
}
} // namespace b

To remove ambiguity, you might full qualify the call:
b::operator <<(std::cout, e) << std::endl;
Not really fine with operator though, I agree.

Related

Compile time overloading for ostream operator

I am trying to introduce the overloading mechanism based on rank of the object.
I managed to implement simple example based on other post and it works for simple types:
https://coliru.stacked-crooked.com/a/8129de0ae8a71af1
Now I would like to do sth similar for custom type:
#include <iostream>
#include <type_traits>
#include <sstream>
class Foo {
};
template < class T,
typename std::enable_if <(std::rank<T>::value == 0), int>::type = 0 >
void f(std::ostream& os, const T& value)
{
os << "rank: 0" << std::endl;
}
template< class T,
typename std::enable_if<(std::rank<T>::value == 1), int>::type = 0 >
void f(std::ostream& os, const T& value)
{
os << "rank: 1" << std::endl;
}
template <class T>
std::ostream& operator<<(std::ostream& os, const T& foo)
{
f<decltype(foo)>(os, foo);
return os;
}
int main()
{
Foo foo0;
Foo foo1[5];
//std::cout << std::rank<decltype(foo0)>{} << "\n"; // 0
//std::cout << std::rank<decltype(foo1)>{} << "\n"; // 1
// correct
f<decltype(foo0)>(std::cout, foo0); //prints: rank: 0
f<decltype(foo1)>(std::cout, foo1); //rank: 1
// invalid
std::cout << foo0; //prints: rank: 0
std::cout << foo1; //rank: 0
return 0;
}
https://coliru.stacked-crooked.com/view?id=cf91cec14a111f70
When I am calling functions directly, I am receiving valid results, but when I am doing it by << each time I am getting 0.
Could you explain what I am doing wrong?
You don't need to use decltype here, just use T:
template<class T>
std::ostream& operator<<(std::ostream& os, const T& foo)
{
f< T >(os, foo);
return os;
}
but when using decltype you will have to remove reference from foo type:
template<class T>
std::ostream& operator<<(std::ostream& os, const T& foo)
{
f< std::remove_reference_t< decltype(foo) > >(os, foo);
return os;
}
When template type deduction works T is deduced to be Foo [5] - what rank supports. But when you do decltype(foo), it returns type also with const & - so you have const Foo (&)[4]. rank for that thing just doesn't work.

Template argument not deduced for inner class

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

How do I overload operators for some specific data types?

Consider this code
#include <bits/stdc++.h>
using namespace std;
struct foo {
template <typename T>
foo& operator<< (const T& var) {
cout << var;
return *this;
}
} bar;
int main() {
bar << 1 << '\n';
bar << 1.2 << '\n';
return 0;
}
I want to overload << operator only for integer data types. (int16_t, int32_t, int64_t)
How can I do that?
You can use SFINAE to ensure that T is an integral type:
template <typename T>
std::enable_if_t<std::is_integral<T>::value, foo&>
operator<< (const T& var) {
cout << var;
return *this;
}
Alternatively, you can use static_assert:
template <typename T>
foo& operator<< (const T& var) {
static_assert(std::is_integral<T>::value, "T must be an integral type");
cout << var;
return *this;
}
Note that you should not #include anything from the bits folder, that's non-portable.
If you want separate overloads for integral and floating point types, you can make two overloads and select with SFINAE:
template <typename T>
std::enable_if_t<std::is_integral<T>::value, foo&>
operator<< (const T& var) {
cout << "int " << var;
return *this;
}
template <typename T>
std::enable_if_t<std::is_floating_point<T>::value, foo&>
operator<< (const T& var) {
cout << "float " << var;
return *this;
}
When we get Concepts you'll be able to write something like this:
template <Integral T>
// ^^^^^^^^ Integral rather than typename
foo& operator<< (const T& var) {
cout << var;
return *this;
}

How to implement a << interface in C++?

I'm working on a tiny compiler, and I use boost::variant<bool, ClassA> infoto store the information of each node.
boost::variant will automatically call the correct << operator of a specific type when I call std::cout<< node.info;
However, since the built-in formatting function of ostream doesn't satisfy my requirement(print #t instead of 1 if node.info==true and print "string" instead of string), new types of bool/string should be introduced.
I want to implement a template class Wrapper<T>, which behaves just like T(because there are lots of old code) and provides the interface of <<.
At first, the following version was implemented:
template<typename T> class Wrapper : public T
{
public:
template<typename ... U> Wrapper(const U& ... a):T(a...) {}
friend std::ostream& operator <<(std::ostream& o, const Wrapper<T>& w);
};
This version works well for std::string, but when T=bool, since built-in types cannot be inherited, an error will raise.
My current workaround is to use partial specialization:
template<typename T, bool ISCLASS= std::is_class<T>::value> class Wrapper;
template<typename T> class Wrapper<T, false>
{
private:
T inner;
public:
template<typename ... U> Wrapper(const U& ... a): inner(a...) {}
//Wrap the operators (= + += ...)
template<typename U> Wrapper<T> operator !() { Wrapper<T> res(*this); res.inner=!res.inner; return res; }
operator T() const{ return inner; }
friend std::ostream& operator <<(std::ostream& o, const Wrapper<T>& w);
};
template<typename T> class Wrapper<T, true> : public T
{
public:
template<typename ... U> Wrapper(const U& ... a):T(a...) {}
friend std::ostream& operator <<(std::ostream& o, const Wrapper<T>& w);
};
Obviously it is not a perfect solution because I have to wrap every operators of bool or any other built-in types.
Any help would be appreciated.
Thanks.
Could we consider something simpler?
Create a simple wrapper, using reference or pointer.
template <class T>
struct MyFormattingWrapper
{
const T& nucleus;
};
And then a factory function for it.
template <class T>
MyFormattingWrapper<T> my_formatting(const T& n)
{
return MyFormattingWrapper<T>{ n };
}
And then, you can specialize the formatting for each type.
std::ostream& operator << (std::ostream& o, const MyFormattingWrapper<int>& w)
{
return o << "int:" << w.nucleus;
}
std::ostream& operator << (std::ostream& o, const MyFormattingWrapper<std::string>& w)
{
return o << "std::string:" << w.nucleus;
}
int main()
{
std::cout << my_formatting(123) << std::endl;
std::cout << my_formatting(std::string{ "abc" }) << std::endl;
}
Update:
C-string may be a special case. But it is not difficult.
struct MyFormattingWrapper_c_string
{
const char* const nucleus;
};
MyFormattingWrapper_c_string my_formatting(const char* n)
{
return MyFormattingWrapper_c_string{ n };
}
MyFormattingWrapper_c_string my_formatting(char* n)
{
return MyFormattingWrapper_c_string{ n };
}
std::ostream& operator << (std::ostream& o, const MyFormattingWrapper_c_string& w)
{
return o << "c-string:" << w.nucleus;
}
Nicky C's answer is great, but has an issue with partial specialization of functions not being OK. This means you can't produce a version that works on general vectors like this:
template<typename T>
std::ostream& operator << (std::ostream& o, const MyFormattingWrapper<std::vector<T>>& vec)
{
o << "vec:[ "
for(auto v : vec) {
o<<my_formatting(v);
o<<" ";
}
return o<<"]"
}
You can get around this by putting the core of the specialized output into the MyFormattingWrapper classes and having only one operator<<
// The default one
template <class T> struct MyFormattingWrapper {
const T& nucleus;
ostream& output(ostream & os) {
return os<<nucleus;
}
};
// Specialized for string
template <> struct MyFormattingWrapper<std::string> {
const std::string& nucleus;
ostream& output(ostream & os) {
return os<<"string:"<<nucleus;
}
};
// Specialized for vector
template <class T> struct MyFormattingWrapper<std::vector<T>> {
const std::vector<T>& nucleus;
ostream& output(ostream & os) {
os<<"vec:[";
for(auto & v: nucleus) {
os<<my_formatting(v)<<" ";
}
return os<<"]";
}
};
// Now there's just one of these, so partial template
// specialization doesn't cause us any problems
template<typename T>
std::ostream& operator << (std::ostream& os, const MyFormattingWrapper<T>& w) {
return w.output(os);
}
Perhaps I better make the follow-up regarding boost::variant another answer.
Firstly, learning from #MichaelAnderson, and considering the interoperability with boost::variant, I would like to improve the design of the wrapper. We add a constructor to enable type conversion for from the nucleus type to the wrapper type.
template <class T>
class MyFormatting;
template <class T>
MyFormatting<T> my_formatting(const T& n)
{
return MyFormatting <T>{n};
}
// int
template <>
class MyFormatting<int>
{
private:
const int& nucleus;
public:
MyFormatting(const int& n) : nucleus(n) {}
friend std::ostream& operator << (std::ostream& os, const MyFormatting& w)
{
return os << "int:" << w.nucleus;
}
};
// std::string
template <>
class MyFormatting<std::string>
{
private:
const std::string& nucleus;
public:
MyFormatting(const std::string& n) : nucleus(n) {}
friend std::ostream& operator << (std::ostream& os, const MyFormatting& w)
{
return os << "std::string:" << w.nucleus;
}
};
// c-string
template <>
class MyFormatting<char*>
{
private:
const char* nucleus;
public:
MyFormatting(const char* n) : nucleus(n) {}
friend std::ostream& operator << (std::ostream& os, const MyFormatting& w)
{
return os << "c-string:" << w.nucleus;
}
};
MyFormatting<char*> my_formatting(const char* n)
{
return MyFormatting<char*>{n};
}
// std::vector
template <class T>
class MyFormatting<std::vector<T>>
{
private:
const std::vector<T>& nucleus;
public:
MyFormatting(const std::vector<T>& n) : nucleus(n) {}
friend std::ostream& operator << (std::ostream& os, const MyFormatting& w)
{
os << "std::vector:[";
for (const auto& x : w.nucleus)
{
os << x << " ";
}
os << "]";
return os;
}
};
Next, let's use the wrapper with boost::variant. The constructor of the wrapper enables conversion between variant of nuclues types to variant of the wrappers.
boost::variant<int, std::string> var_int = 50;
boost::variant<int, std::string> var_str = "fifty";
boost::variant<MyFormatting<int>, MyFormatting<std::string>> var_fmt_int = var_int;
boost::variant<MyFormatting<int>, MyFormatting<std::string>> var_fmt_str = var_str;
std::cout << var_int << " " << var_str << std::endl;
std::cout << var_fmt_int << " " << var_fmt_str << std::endl;
But boost::variant<MyFormatting<int>, MyFormatting<std::string>> spells too long. We can make it shorter.
template <class... T>
using Variant_Formatting_t = boost::variant < MyFormatting<T>... > ;
std::cout << Variant_Formatting_t<int, std::string>{var_int} << " " << Variant_Formatting_t<int, std::string>{var_str} << std::endl;
Since boost::variant use macro-template metaprogramming to emulate variadic template instead of using C++11 variadic template, I cannot make it cleaner using type deduction. This is the furthest I can get to.

call my template operator<< only if no other found

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;
}