打印对象的文本表示

时间:2014-10-20 03:26:58

标签: c++ templates operator-overloading

我对C ++比较陌生。如果不正确,请原谅我的术语。我试着寻找我的问题的答案,但我找不到它(可能是因为我无法正确地说出我的问题)。如果有人可以帮助我,我会很感激。

我正在尝试编写一个类来创建可能包含对象或本机类型的文本表示的字符串。基本上,我有

private:
    stringstream ss;


public:
    template< typename T >
    Message& operator<<( const T& value ) {
        ss << value;
        return *this;
    }

重载&lt;&lt;运算符取一些值并尝试将其流式传输到字符串流中。如果T类似int或类T定义方法operator std::string(),我认为我的编译器可以正常使用。但是,如果T类型为vector<int>,则它不再有效,因为vector<int>没有定义operator std::string()

无论如何我可能会重载此运算符,以便T定义operator std::string(),然后我打印文本表示,如果它没有,我只打印它的地址?< / p>

感谢。

2 个答案:

答案 0 :(得分:2)

这可以通过构建此处描述的has_insertion_operator类型特征来实现:https://stackoverflow.com/a/5771273/4323

namespace has_insertion_operator_impl {
typedef char no;
typedef char yes[2];

struct any_t {
  template<typename T> any_t( T const& );
};

no operator<<( std::ostream const&, any_t const& );

yes& test( std::ostream& );
no test( no );

template<typename T>
struct has_insertion_operator {
  static std::ostream &s;
  static T const &t;
  static bool const value = sizeof( test(s << t) ) == sizeof( yes );
};
}

template<typename T>
struct has_insertion_operator :
  has_insertion_operator_impl::has_insertion_operator<T> {
};

一旦我们有了,其余的相对简单:

class Message
{
  std::ostringstream ss;

public:
  template< typename T >
  typename std::enable_if<has_insertion_operator<T>::value, Message&>::type
  operator<<( const T& value ) {
    ss << value;
    return *this;
  }

  template< typename T >
  typename std::enable_if<!has_insertion_operator<T>::value, Message&>::type
  operator<<( const T& value ) {
    ss << &value;
    return *this;
  }
};

也就是说,如果定义了插入运算符,则打印该值,否则打印其地址。

这不依赖于定义转换为 - std::string运算符 - 您只需要确保T实例使用operator <<“可打印”(通常在定义每个T的相同范围,例如命名空间或全局范围)。

答案 1 :(得分:1)

以下是一个示例 - 将转化运算符的某些自定义特征用于std::string和流媒体运算符:

#include <iostream>
#include <string>

template <class T>
struct traits
{
    template <typename Q>
    static auto hos(Q*) -> decltype(std::declval<const Q>().operator std::string());

    static char hos(...);

    constexpr static bool has_operator_string =
        sizeof hos((T*){0}) != 1;

    // ----

    template <typename Q>
    static auto isab(Q*) -> decltype(std::cout << std::declval<const Q>());

    static char isab(...);


    constexpr static bool is_streamable =
        sizeof isab((T*){0}) != 1;
};

struct S
{
    template <typename T>
    typename std::enable_if<
                 traits<T>::has_operator_string,
                 S&>::type
    operator<<(const T& value)
    {
        std::cout << "string() " << value.operator std::string() << '\n';
        return *this;
    }    

    template <typename T>
    typename std::enable_if<!traits<T>::has_operator_string && traits<T>::is_streamable, S&>::type
    operator<<(const T& value)
    {
        std::cout << "<< " << value << std::endl;
        return *this;
    }

    template <typename T>
    typename std::enable_if<
                 !traits<T>::has_operator_string &&
                 !traits<T>::is_streamable,
                 S&>::type
    operator<<(const T& value)
    {
        std::cout << "T& @" << &value << std::endl;
        return *this;
    }
};

struct X
{
    operator std::string() const { return "hi"; }
};

struct Y
{

};

int main()
{
    std::cout << "> main()" << std::endl;

    std::cout << "X() ";
    S() << X();

    Y y;
    std::cout << "Y y; ";
    S() << y;

    std::cout << "Y() ";
    S() << Y();

    std::cout << "\"text\" ";
    S() << "text";
    std::cout << "< main()" << std::endl;
}