2014-10-20 6 views
3

Я относительно не знаком с C++. Пожалуйста, извините мою терминологию, если она неверна. Я попытался найти ответ на свой вопрос, но я не мог его найти (возможно, потому, что я не мог правильно сформулировать свой вопрос). Я был бы признателен, если бы кто-то мог мне помочь.Печать текстового представления объектов

Я пытаюсь написать класс для создания строк, которые могут содержать текстовое представление объектов или родных типов. По сути, у меня есть

private: 
    stringstream ss; 


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

Перегруженный < < оператор принимает некоторое значение и пытается транслировать его в stringstream. Я думаю, что мой компилятор в порядке с этим, если T что-то вроде int, или если класс T определяет метод operator std::string(). Однако, если T - это какой-то тип, такой как vector<int>, то он больше не работает, потому что vector<int> не определяет operator std::string().

В любом случае я мог бы перегрузить этот оператор так, чтобы, если T определяет operator std::string(), тогда я печатаю текстовое представление, а если нет, я просто печатаю его адрес?

Спасибо.

ответ

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

То есть, если есть задан оператор вставки, напечатайте значение, иначе распечатайте его адрес.

Это не зависит от конверсионного-to-std::string оператора определяется - вам нужно только, чтобы убедиться, что ваши T экземпляры «версия для печати» с использованием operator << (обычно реализуется в том же объеме, в котором каждый T определяется, например, пространство имен или глобальный охват).

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; 
} 
Смежные вопросы