3

Is it possible to have a templated generic <<ostream operator which would work for any class which owns a to_string() method ? For instance the following code :

#include <iostream>
#include <string>

struct A {
    int a;
    std::string to_str() const { return std::to_string(a); }
};

struct B {
    std::string b;
    std::string to_str() const { return b; }
};

template<class Stringifiable>
std::ostream& operator<< (std::ostream& os, const Stringifiable& s) {
    os << s.to_str();
    return os;
}

int main() {
    A a{3};
    B b{"hello"};
    std::cout << a << b << std::endl;
}

does not compile. Errors given are of the type :

prog.cpp: In instantiation of 'std::ostream& operator<<(std::ostream&, const Stringifiable&) [with Stringifiable = A; std::ostream = std::basic_ostream<char>]':
prog.cpp:23:15:   required from here
prog.cpp:16:5: error: ambiguous overload for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'std::string {aka std::basic_string<char>}')
  os << s.to_str();
coincoin
  • 4,595
  • 3
  • 23
  • 47
  • 2
    You might be able to solve this with SFINAE and type traits, but I really think you could save yourself a lot of delicate coding by just using dynamic polymorphism here and making `Stringifiable` an abstract base class. Life's too short to be finding compile-time solutions for everything. –  May 27 '15 at 16:19
  • Thank you Ike for your proposition. So every stringifiable classes has to be derived from `Stringifiable` ? It seems like I would need to write quite some codes which would not be really different from the "classical" way. I woud like to avoid that. I also may have misunderstood your point. – coincoin May 27 '15 at 16:25
  • The answers in the duplicate check for `to_string(T{})`, you need to check for `T{}.to_str()`, but basically same idea. – Barry May 27 '15 at 16:36

0 Answers0