1

I am writing code to compare to instances of various types. The final comparison function is quite simple - with signature:

template <typename T>
int not_equal(const T& arg1, const T& arg2) {
    if (arg1 == arg2)
        return 0;

    std::cerr << "Error when comparing" << std::endl;
    return 1;
}

Now - I would like to add the actual values being compared in the std::cerr message as:

std::cerr << "Error when comparing " << arg1 << " != " << arg2 << std::endl;

however - many of the classes do not have operator<< - and that is OK. For the classes which do not support operator<< I just want the classname - i.e. the pseudo code should be something like:

if (supports_operator<<<T>)
    std::cerr << "Error when comparing " << arg1 << " != " << arg2 << std::endl;
else
    std::cerr << "Error when comparing instances of type: " << typeid(arg1).name() << std::endl;

Can I have my fictitious supports_operator<<<T>()functionality?

Edit: I am limited to C++17

Andreas
  • 5,393
  • 9
  • 44
  • 53
user422005
  • 1,989
  • 16
  • 34
  • does this answer your question? https://stackoverflow.com/a/39348287/10794806 – Gaurav Dhiman Feb 19 '20 at 13:42
  • Why not used [this method](https://stackoverflow.com/a/6536204/1593077)? Should work just as well for `operator<<` as for `operator==`. – einpoklum Feb 19 '20 at 13:54
  • I am trying to go through the "check whether operator== exists" post; I must admit the answers are slightly above my C++ pay grade - although I agree I should be able to utilize the answers - looking into it. – user422005 Feb 19 '20 at 13:57
  • Check this out: https://godbolt.org/z/j-WFTx – VLL Feb 19 '20 at 14:01
  • Thanks for the example - I think that solves. – user422005 Feb 19 '20 at 14:07
  • Note: with `concepts` (available with gcc *before* C++20), you can overload a given function, for types accepting or not `<<`, in an automatic and very simple way. I prepared a simple answer, too late! – Damien Feb 19 '20 at 14:18

1 Answers1

0

If you are able to use C++20 and concepts, then you can do something like this:

#include <iostream>
#include <concepts>

template <typename T> 
concept Streamable = requires (T x) { std::cout << x; };

struct Foo {};
struct Bar {};

std::ostream& operator<<(std::ostream& os, Foo const& obj) {
    // write obj to stream
    return os;
}

template <Streamable T>
void foo(T const& t) {
    std::cout << t << std::endl;
}

int main() {
    Foo f;
    Bar b;

    foo(f);
    foo(b); // error

    return 0; 
}

Demo

NutCracker
  • 11,485
  • 4
  • 44
  • 68