Is there way out of this ambiguity? - c++

Consider this (rather) simple example:
#include <iostream>
struct Out {
int value;
};
template<class Sink> decltype(auto) operator<<(Sink &&s, Out const &out) {
return out.value > 0? s << out.value : s;
}
struct In {
std::ostream &sink;
template<typename T> In &operator<<(T const &t) {
return sink << t, *this;
}
};
int main() {
In in{std::cout};
in << (1 << Out{3}) << '\n'; // Ok
in << Out{42} << '\n';
// error: use of overloaded operator '<<' is ambiguous
// (with operand types 'In' and 'Out')
}
Can such an ambiguity be addressed? We have two classes, each one defines such an operator overload to forward it to its internal type (classes are designed independently by two different people, and another person tries to use them in the same application.) I don't see a way this could be reformulated in terms of other operators, say, it's no use here to give up on A's friend operator<< and try to convert A to int; and to use some kind of complicated SFINAE to rule out some overloads still doesn't look helpful.

You might create additional overloads which would be the better match:
decltype(auto) operator<<(In& in, Out const &out) {
return in.operator<<(out);
}
decltype(auto) operator<<(In&& in, Out const &out) {
return in.operator<<(out);
}

Some semi-oldschool SFINAE seemingly does the trick, in the sense that it is now accepted by both gcc and clang (and they both print "8" and "42" equally):
#include <iostream>
#include <utility>
template<typename S, typename T> class can_shl {
using Left = char;
struct Right { char c[2]; };
template<typename U> static constexpr decltype(
std::declval<S>() << std::declval<U>(), Left{})
has_it(U &&);
static constexpr Right has_it(...);
public:
static constexpr bool value = sizeof(has_it(std::declval<T>())) == 1;
};
struct Out {
int value;
};
template<class Sink> auto operator<<(Sink &&s, Out const &out)
-> std::enable_if_t<!can_shl<Sink, Out>::value, decltype(out.value > 0? s << out.value : s)>
{
return out.value > 0? s << out.value : s;
}
struct In {
std::ostream &sink;
template<typename T> In &operator<<(T const &t) {
return sink << t, *this;
}
};
int main() {
In in{std::cout};
in << (1 << Out{3}) << '\n'; // Ok
in << Out{42} << '\n';
}
Personally I don't feel quite confident with that "only allow this in case it does not compile on its own" approach (is this perchance a (static) UB? what would I say if I were a C++ standard?)

Related

Compiler differences with use of templated overloads

I have a pretty specific situation where I'm feeding a bunch of data to a hasher-like class. In particular, one data type that I use has a member whose type depends on the supertype's type parameter. Long story short, here's a piece of code that illustrates this behaviour :
#include <assert.h>
#include <iostream>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
// Some dummy priority structs to select overloads
struct priority0 { };
struct priority1 : priority0 { };
// This is the hasher-like function
struct Catcher
{
// Ideally we feed everything to this object through here
template <typename T> Catcher& operator<<(const T& v)
{
add(v, priority1{}); // always attempt to call the highest-priority overload
return *this;
}
// For floating-point data types
template <typename T> auto add(const T& v, priority1) -> std::enable_if_t<std::is_floating_point_v<T>, void>
{
std::cout << "caught float/double : " << v << std::endl;
}
// For ranges
template <class T> auto add(const T& range, priority1) -> decltype(begin(range), end(range), void())
{
for(auto const& v : range)
*this << v;
}
// For chars
void add(char c, priority1)
{
std::cout << c;
std::cout.flush();
}
// When everything else fails ; ideally should never happen
template <typename T> void add(const T& v, priority0)
{
assert(false && "should never happen");
}
};
// The one data type. Notice how the primary template and the
// specialization have a `range` member of different types
template <class T> struct ValueOrRange
{
struct Range
{
T min;
T max;
};
Range range;
T value;
};
template <> struct ValueOrRange<std::string>
{
std::vector<std::string> range;
std::string value;
};
// Overload operator<< for Catcher outside of the
// class to allow for processing of the new data type
// Also overload that for `ValueOrRange<T>::Range`. SFINAE should make sure
// that this behaves correctly (?)
template <class T> Catcher& operator<<(Catcher& c, const typename ValueOrRange<T>::Range& r)
{
return c << r.min << r.max;
}
template <class T> Catcher& operator<<(Catcher& c, const ValueOrRange<T>& v)
{
return c << v.range << v.value;
}
int main(int argc, char *argv[])
{
ValueOrRange<std::string> vor1{{}, "bleh"};
ValueOrRange<float> vor2{{0.f, 1.f}, 0.5f};
Catcher c;
c << vor1; // works fine, displays "bleh"
c << vor2; // fails the assert in Catcher::add(const T&, priority0) with T = ValueOrRange<float>::Range
return 0;
}
While the line c << vor1 gets resolved correctly through the various overloads and has the intended effect, the second line c << vor2 fails the assert.
What I want to happen : c << vor2 calls Catcher& operator<<(Catcher& s, const ValueOrRange<float>& v), which in turn calls Catcher& operator<<(Catcher& s, const typename ValueOrRange<float>::Range& r)
What does happen : instead of Catcher& operator<<(Catcher& s, const typename ValueOrRange<float>::Range& r), it is Catcher& Catcher::operator<<(const T& v) with T = typename ValueOrRange<float>::Range that is called, and thus the assert fails.
Worthy of note is that this same code has the intended effect on MSVC, and fails the assert on GCC.
Any idea on how I should fix that ?
Thanks to feedback from Igor Tandetnik, I got rid of the ::Range-specific overload and simply went for checking std::is_same_v<T, std::string>. A little less modular than I'd like, but it'll do the trick.
// A single function will do the trick
template <class T> Catcher& operator<<(Catcher& c, const ValueOrRange<T>& v)
{
if constexpr (std::is_same_v<T, std::string>)
c << v.range;
else
c << v.range.min << v.range.max;
return c << v.value;
}
In Catcher& operator<<(Catcher& c, const typename ValueOrRange<T>::Range& r), T in non deducible.
One work around would be friend function:
template <class T> struct ValueOrRange
{
struct Range
{
T min;
T max;
friend Catcher& operator<<(Catcher& c, const Range& r)
{
return c << r.min << r.max;
}
};
Range range;
T value;
};
Demo

variadic template for << operator for simple logger

Can you help me with the following problem ?
I am trying to use the variadic templates and pack expansion to write a logger. The problem is I know that operator<< must accept only two arguments - the second argument then becomes a whole pack, and I do not know how to expand 'const Args& ...rest' to 'const T& v, const Args& ...rest'
Can any guru explain how to re-write the variadic expression to achieve this goal ? The end game is to have code like:
log << "string" << 1 << 1.2;
being printed together at once.
(Please excuse the cout, it is just for example purposes. Idea is to collect all the arguments in oss_ and then print them once.).
The compiler current complains, which I understand is the issue with operator<< accepting only two arguments.
‘LogHandle& operator<<(LogHandle&, const T&, const Args& ...)’ must take exactly two argument
Here is the code:
#include <iostream>
#include <string>
#include <sstream>
class LogHandle {
public:
template<typename T>
friend LogHandle& operator<<(LogHandle& l, const T& v)
{
l.oss_ << v;
std::cout << "Value is: " << l.oss_.str().c_str();
l.oss_.str("");
l.oss_.clear();
return l;
}
template<typename T, typename... Args>
friend LogHandle& operator<<(LogHandle& l, const T& v, const Args&... rest)
{
l.oss_ << v << " ";
return l << (rest...);
}
std::ostringstream oss_;
};
int main(int, char**)
{
LogHandle log;
log << "String" << 1;
}
What you want to do is not possible exactly the way you want it, because the arity of operators is fixed—you cannot make them variadic.
However, you can instead use a proxy returned from your operator << to "collect" all the arguments in one place. Something like this:
class LogHandle
{
template<typename T>
friend LogProxy operator<<(LogHandle& l, const T& v)
{
LogProxy p(*this);
p << v;
return p;
}
void print(const std::ostringstream &oss)
{
std::cout << "Value is: " << oss.str();
}
};
struct LogProxy
{
LogHandle *handle;
std::ostringstream oss_;
LogProxy(LogHandle &l) : handle(&l) {}
LogProxy(LogProxy &&rhs) : handle(rhs.handle) { rhs.handle = nullptr; }
template <class T>
friend LogProxy& operator<< (LogProxy &p, const T &v)
{
p.oss_ << v;
return p;
}
~LogProxy()
{
if (handle) handle->print(oss_);
}
};

Printing textual representation of objects

I'm relatively new to C++. Please excuse my terminology if it's incorrect. I tried searching around for an answer to my question, but I could not find it (probably because I couldn't phrase my question correctly). I'd appreciate it if someone could help me.
I am trying to write a class for creating strings that might contain the textual representation of objects or native types. Essentially, I have
private:
stringstream ss;
public:
template< typename T >
Message& operator<<( const T& value ) {
ss << value;
return *this;
}
The overloaded << operator takes some value and tries to stream it into a stringstream. I think my compiler is fine with this if the T is something like int or if the class T defines the method operator std::string(). However, if T is some type like vector<int>, then it no longer works because vector<int> doesn't define operator std::string().
Is there anyway I could perhaps overload this operator so that if T defines operator std::string(), then I print the textual representation, and if it doesn't, I just print its address?
Thanks.
This can be implemented by building upon the has_insertion_operator type trait described here: https://stackoverflow.com/a/5771273/4323
namespace has_insertion_operator_impl {
typedef char no;
typedef char yes[2];
struct any_t {
template<typename T> any_t( T const& );
};
no operator<<( std::ostream const&, any_t const& );
yes& test( std::ostream& );
no test( no );
template<typename T>
struct has_insertion_operator {
static std::ostream &s;
static T const &t;
static bool const value = sizeof( test(s << t) ) == sizeof( yes );
};
}
template<typename T>
struct has_insertion_operator :
has_insertion_operator_impl::has_insertion_operator<T> {
};
Once we have that, the rest is relatively straightforward:
class Message
{
std::ostringstream ss;
public:
template< typename T >
typename std::enable_if<has_insertion_operator<T>::value, Message&>::type
operator<<( const T& value ) {
ss << value;
return *this;
}
template< typename T >
typename std::enable_if<!has_insertion_operator<T>::value, Message&>::type
operator<<( const T& value ) {
ss << &value;
return *this;
}
};
That is, if there is an insertion operator defined, print the value, otherwise print its address.
This does not rely on a conversion-to-std::string operator being defined--you only need to make sure your T instances are "printable" using operator << (typically implemented in the same scope where each T is defined, e.g. namespace or global scope).
Here's an example - using some custom traits for a conversion operator to std::string and the streaming operator:
#include <iostream>
#include <string>
template <class T>
struct traits
{
template <typename Q>
static auto hos(Q*) -> decltype(std::declval<const Q>().operator std::string());
static char hos(...);
constexpr static bool has_operator_string =
sizeof hos((T*){0}) != 1;
// ----
template <typename Q>
static auto isab(Q*) -> decltype(std::cout << std::declval<const Q>());
static char isab(...);
constexpr static bool is_streamable =
sizeof isab((T*){0}) != 1;
};
struct S
{
template <typename T>
typename std::enable_if<
traits<T>::has_operator_string,
S&>::type
operator<<(const T& value)
{
std::cout << "string() " << value.operator std::string() << '\n';
return *this;
}
template <typename T>
typename std::enable_if<!traits<T>::has_operator_string && traits<T>::is_streamable, S&>::type
operator<<(const T& value)
{
std::cout << "<< " << value << std::endl;
return *this;
}
template <typename T>
typename std::enable_if<
!traits<T>::has_operator_string &&
!traits<T>::is_streamable,
S&>::type
operator<<(const T& value)
{
std::cout << "T& #" << &value << std::endl;
return *this;
}
};
struct X
{
operator std::string() const { return "hi"; }
};
struct Y
{
};
int main()
{
std::cout << "> main()" << std::endl;
std::cout << "X() ";
S() << X();
Y y;
std::cout << "Y y; ";
S() << y;
std::cout << "Y() ";
S() << Y();
std::cout << "\"text\" ";
S() << "text";
std::cout << "< main()" << std::endl;
}

Is there a way to find out if a class has an overloaded operator?

I am writing a template class where I need a method to print out element class into stdout. But I am having a problem writing it - what if cout << or operator const char*() is not defined or overloaded in my element class?
Is there a way to find it out to maybe throw an exception and not get compilation error?
If the operator is not overloaded, your program can not compile. This is a compile time error and there is no way to delay that until runtime.
A way around would be to not use an operator, but a function pointer. If the operation is not supported, than the function pointer could be set to 0 which you can detect at runtime.
class A {
public:
int q; // some data
typedef std::function<void(std::ostream& os, const A&)> PrinterFunc;
PrinterFunc func;
friend std::ostream& operator<<(std::ostream& os, const A& a) {
if(!a.func) {
throw "Not supported";
}
func(os,a);
return os;
}
};
A a;
a.func = [](std::ostream& os, const A& a) { os << "hello " << a.q; }
std::cout << a << std::endl; // will print
A b;
std::cout << b << std::endl; // will throw
This example uses C++11 and <functional>. For C++03 you would have to use a "normal" function pointer.
You might use some SFINAE to test if an (formatted) output operator exists:
#include <iostream>
// HasFormattedOutput
// ============================================================================
namespace HasFormattedOutput {
namespace Detail
{
struct Failure{};
}
template<typename OutputStream, typename T>
Detail::Failure operator << (OutputStream&, const T&);
template<typename OutputStream, typename T>
struct Result : std::integral_constant<
bool,
! std::is_same<
decltype(std::declval<OutputStream&>() << std::declval<T>()),
Detail::Failure
>::value
> {};
} // namespace HasFormattedOutput
template <typename T, typename OutputStream = std::ostream>
struct has_formatted_output : std::conditional<
HasFormattedOutput::Result<OutputStream, T>::value,
std::true_type,
std::false_type>::type
{};
// Test
// ============================================================================
struct X {};
int main() {
std::cout.setf(std::ios_base::boolalpha);
std::cout << has_formatted_output<const char*>() << '\n';
std::cout << has_formatted_output<X>() << '\n';
}
(C++11)

templates, decltype and non-classtypes

I have a function definition like so
template <typename T>
auto print(T t) -> decltype(t.print()) {
return t.print();
}
The idea is that the argument must be of type T and must have the print function. This print function could return anything, explaining the need of decltype. So for example you can do:
struct Foo
{
int print()
{
return 42;
}
};
struct Bar
{
std::string print()
{
return "The answer...";
}
};
...
std::cout << print(Foo()) << std::endl;
std::cout << print(Bar()) << std::endl;
/* outputs:
42
The answer...
*/
I read that templates cannot do runtime instantiation and that you can have the classes derive from a base class, then determine their types to see what template argument to use. However, how would I do this for a non-class type? The idea is to be able to have:
template <typename T>
T print(T t) {
return t;
}
as well, but this gives me ambiguous overload errors. Qualifying doesn't work, ie print<Foo>. And the other got'cha is, what if I had a functor like:
struct Foo
{
virtual int print();
operator int() const
{
return 42;
}
};
How does it decide now?
So my question is, is it possible to resolve all these ambiguities with templates, or do I have to write a bunch of redundant code?
Tests
I incrementally added tests, copy/pasting each edit'ed solution from below. Here are the results:
With the following classes:
struct Foo
{
int print()
{
return 42;
}
operator int() const
{
return 32;
}
};
struct Bar
{
std::string print()
{
return "The answer...";
}
operator int() const
{
return (int)Foo();
}
};
struct Baz
{
operator std::string() const
{
return std::string("The answer...");
}
};
And the following test output:
std::cout << print(Foo()) << std::endl;
std::cout << print(Bar()) << std::endl;
std::cout << print(42) << std::endl;
std::cout << print((int)Foo()) << std::endl;
std::cout << print("The answer...") << std::endl;
std::cout << print(std::string("The answer...")) << std::endl;
std::cout << print((int)Bar()) << std::endl;
std::cout << print((std::string)Baz()) << std::endl;
Both correctly output:
42
The answer...
42
32
The answer...
The answer...
32
The answer...
You could adopt the following approach, which invokes a print() member function on the input if such a member function exists, otherwise it will return the input itself:
namespace detail
{
template<typename T, typename = void>
struct print_helper
{
static T print(T t) {
return t;
}
};
template<typename T>
struct print_helper<T, decltype(std::declval<T>().print(), (void)0)>
{
static auto print(T t) -> decltype(t.print()) {
return t.print();
}
};
}
template<typename T>
auto print(T t) -> decltype(detail::print_helper<T>::print(t))
{
return detail::print_helper<T>::print(t);
}
Here is a live example.
Simple solution using manual overloading for each type which you want to print directly:
Define your first implementation which calls T::print(). Use overloading to specify alternative implementations for all types which don't have this function. I don't recommend this solution, but it's very easy to understand.
template<typename T>
auto print(T t) -> decltype(t.print()) {
return t.print();
}
int print(int t) {
return t;
}
std::string print(std::string t) {
return t;
}
// ... and so on, for each type you want to support ...
More advanced solution using SFINAE which uses T::print() automatically if and only if it's there:
First, define a trait which can decide if your type has a function print(). Basically, this trait inherits from either std::true_type or std::false_type, depending on the decision being made in some helper class (_test_print). Then, use this type trait in an enable_if compile-time decision which defines only one of the two cases and hides the other one (so this is not overloading).
// Type trait "has_print" which checks if T::print() is available:
struct _test_print {
template<class T> static auto test(T* p) -> decltype(p->print(), std::true_type());
template<class> static auto test(...) -> std::false_type;
};
template<class T> struct has_print : public decltype(_test_print::test<T>(0)) {};
// Definition of print(T) if T has T::print():
template<typename T>
auto print(T t) -> typename std::enable_if<has_print<T>::value, decltype(t.print())>::type {
return t.print();
}
// Definition of print(T) if T doesn't have T::print():
template<typename T>
auto print(T t) -> typename std::enable_if<!has_print<T>::value, T>::type {
return t;
}
Have a look at the live demo.