У меня есть класс, подобный повышению:: любой, в котором это - шаблонный контейнерный класс. Я хотел бы иметь метод для записи содержавшего значения в строку. Однако, если бы содержавший тип не обеспечивает потоковый оператор вставки, я хотел бы, чтобы мой метод возвратил некоторый Тринг по умолчанию вместо того, чтобы не удаться скомпилировать. Ниже так же близко, как я приехал и должен прояснить относительно того, что я пытаюсь сделать:
namespace W {
namespace hide {
template <typename T>
std::ostream& operator<<(std::ostream& out, const T& t) {
return std::operator<<(out, typeid(T).name());
}
}
template <typename T> struct C {
T t_;
std::string ToString() const {
using namespace hide;
std::ostringstream oss;
oss << t_;
return oss.str();
}
};
}
Это работает вполне прилично с некоторыми протестами. Например, если я хочу на самом деле обеспечить перегруженный оператор вставки для класса, затем тот оператор должен или быть в том же пространстве имен как класс, или это должно быть в пространстве имен W для него, чтобы быть рассмотренным.
Это также имеет проблемы с любым типом, который уже имеет не являющийся членом станд.:: оператор <<, например, символ и станд.:: строка. Если T является одним из тех типов, то oss << t_
строка выше становится неоднозначной. Это может работаться вокруг путем добавления перегрузок для этих типов в пространстве имен W, например:
std::ostream& operator << (std::ostream& out, const std::string& s) {
return std::operator <<(out, s);
}
Мой вопрос, кто-либо нашел лучший метод, чем это? Почему делают я должен добавить свои собственные перегрузки для вещей как станд.:: строка? Это все поддерживается согласно стандарту, или я использую в своих интересах нестандартное поведение? (Я тестирую с g ++ 4.3.3),
Ниже приведен код, который я недавно видел в классе построения компилятора. Я думал, что это было особенно умно (если не «чисто»), поэтому я держался за него.
Из http://www.cs.colorado.edu/~main/a++/tree.h
// If data of type T can be printed with the usual << operator, then
// print<T>(out, p) will interpret *p as a T object and print its
// value to out. Otherwise, a message is printed to out, indicating
// that objects of type T are not printable.
template<typename T> void print(std::ostream& out, const void* p)
{
// The first part of this code sets an enum value, is_printable, to
// be 1 if the data type T can be printed with the usual <<
// operator. Otherwise, is_printable is set to zero. The programming
// technique is based on a note from Herb Sutter at
// http://www.gotw.ca/gotw/071.htm
class object
{
public:
object(T convert) { };
};
char operator << (std::ostream&, const object&);
enum { is_printable = sizeof(std::cout << (*static_cast<T*>(0))) == sizeof(char) ? 0 : 1 };
// Notice that the boolean expression in the if-statement is known at
// compile time, so that only one of the two output statements will be
// compiled into object code.
if (is_printable)
out << *static_cast<const T*>(p);
else
out << "(value of type " << typeid(T).name() << " cannot be printed)";
}
Когда вы создаете объект-контейнер, удерживайте указатель на функцию печати для переменной:
void (*printer)(std::ostream&, const void*);
printer = print<T>;
Затем, если возможно, используйте функцию printer (), чтобы отобразить содержащееся значение.
Надеюсь, это поможет.