Этот вопрос следует моему предыдущему вопросу: Generic operator<< ostream C++ for stringifiable class, где я хотел бы реализовать общий оператор <<ostream
, который будет работать для любого класса, которому принадлежит метод to_str()
.C++ неоднозначная перегрузка для общего шаблона ostream << оператор
Мне удалось проверить, реализует ли класс метод to_str()
и использует std::cout << stringify(a)
благодаря этому answer. Тем не менее, у меня возникли трудности с написанием шаблонов ostream<<
операторов, чтобы сделать std::cout << a
работ.
Следующий код теста:
#include <iostream>
#include <sstream>
#include <string>
template<class ...> using void_t = void;
template<typename T, typename = void>
struct has_to_string
: std::false_type { };
template<typename T>
struct has_to_string<T,
void_t<decltype(std::declval<T>().to_str())>
>
: std::true_type { };
template<typename T> std::enable_if_t<has_to_string<T>::value, std::string>
stringify(T t) {
return t.to_str();
}
template<typename T> std::enable_if_t<!has_to_string<T>::value, std::string>
stringify(T t) {
return static_cast<std::ostringstream&>(std::ostringstream() << t).str();
}
// The following does not work
/*
template<typename T> std::enable_if_t<has_to_string<T>::value, std::ostream&>
operator<<(std::ostream& os, const T& t) {
os << t.to_str();
return os;
}
template<typename T> std::enable_if_t<!has_to_string<T>::value, std::ostream&>
operator<<(std::ostream& os, const T& t) {
os << t;
return os;
}
*/
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; }
};
int main() {
A a{3};
B b{"hello"};
std::cout << stringify(a) << stringify(b) << std::endl; // This works but I don't want to use stringify
// std::cout << a << b << std::endl; // I want this but it does not work
}
дает ту же ошибку, как и в исходном вопросе. Что я делаю не так ?
версия с '! Has_to_string :: value' производит бесконечную рекурсию как' зева << T' называет себя. –
Jarod42
Спасибо за ваш вопрос! – coincoin