Общий оператор‹‹ ostream C++ для строкового класса

Возможно ли иметь шаблонный общий оператор <<ostream, который будет работать для любого класса, которому принадлежит метод to_string()? Например, следующий код:

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

не компилируется. Приведены ошибки типа:

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();

person coincoin    schedule 27.05.2015    source источник
comment
Возможно, вы сможете решить эту проблему с помощью SFINAE и свойств типов, но я действительно думаю, что вы могли бы избавить себя от большого количества деликатного кодирования, просто используя здесь динамический полиморфизм и сделав Stringifiable абстрактным базовым классом. Жизнь слишком коротка, чтобы искать решения во время компиляции для всего.   -  person    schedule 27.05.2015
comment
Спасибо, Айк, за твое предложение. Таким образом, все строковые классы должны быть производными от Stringifiable ? Похоже, мне нужно было бы написать довольно много кодов, которые не сильно отличались бы от классического способа. Я хотел бы избежать этого. Я также, возможно, неправильно понял вашу мысль.   -  person coincoin    schedule 27.05.2015
comment
Ответы в дубликате проверки для to_string(T{}) вам нужно проверить для T{}.to_str(), но в основном та же идея.   -  person Barry    schedule 27.05.2015