6

我有一个类似于 boost::any 的类,因为它是一个模板化的容器类。我想要一种将包含的值写入字符串的方法。但是,如果包含的类型不提供流插入运算符,我希望我的方法返回一些默认字符串,而不是编译失败。下面是我已经接近的情况,并且应该清楚地说明我正在尝试做什么:

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 命名空间中才能考虑。

对于已经具有非成员 std::operator<< 的任何类型,例如 char 和 std::string,它也存在问题。如果 T 是这些类型之一,则oss << t_上面的行变得模棱两可。这可以通过在 W 命名空间中为这些类型添加重载来解决,例如:

std::ostream& operator << (std::ostream& out, const std::string& s) {
    return std::operator <<(out, s);
}

我的问题是,有没有人找到比这更好的方法?为什么我必须为 std::string 之类的东西添加自己的重载?这都是根据标准支持的,还是我在利用非标准行为?(我正在使用 g++ 4.3.3 进行测试)

4

1 回答 1

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

然后,如果可能,稍后使用 print() 函数显示包含的值。

希望这可以帮助。

于 2010-01-08T20:24:26.383 回答