2013-01-11 4 views
0

Можно ли реализовать функцию C++, которая дает строковое представление каждого std::vector<T>, до тех пор, как элемент типа T может быть добавлен в выходной поток, какСтроковое представление станд :: вектор <T>

T x; 
... 
std::cout << x << std::endl; 

Строковое представление должно выглядеть

[x, y, z] 

Я попытался следующие, но что должно ? быть?

template <typename T> std::string vectorToString(std::vector<T>& vec) { 
    std::string s; 
    for (T element : vec) { 
     ? 
    } 
    return s; 
} 
+3

См http://stackoverflow.com/questions/4850473/pretty-print-c-stl- контейнеры – Dan

+0

Если вы заинтересованы в реализации этого по своему усмотрению, вы, вероятно, захотите узнать о SFINAE, trailing decltype() и std :: enable_if :) Но это выполнимо, и для этого требуются инструменты выше, чтобы обнаруживать во время компиляции если T является потокобезопасным. – bluescarni

+1

Я думаю, было бы лучше сменить подпись на const ref: vectorToString (** const ** std :: vector < T > & vec) – borisbn

ответ

3

Вы хотите stringstream сделать форматирование:

std::ostringstream ss; 
ss << '[' 
bool first = true; 
for (T const & element : vec) { 
    if (!first) { 
     ss << ", "; 
    } 
    ss << element; 
    first = false; 
} 
ss << ']'; 
return ss.str(); 
+0

+1, но вы, вероятно, захотите взять элемент по ссылке, чтобы избежать ненужного копирования (поскольку 'operator <<' никогда не должен изменять исходный объект): 'for (T const & element: vec)'. –

+0

@ DavidRodríguez-dribeas: Действительно; Я скопировал эту строку из вопроса, не применяя свой мозг. –

0

Немного быстрее версии

template <typename T> std::string vectorToString(const std::vector<T>& vec) { 
    if (vec.empty()) { 
     return "[]"; 
    } 
    std::ostringstream s; 
    s << "[" << vec.front(); 

    for (auto i = vec.begin() + 1, e = vec.end(); i != e; i++) 
    { 
     s << ", " << *i; 
    } 
    s << "]"; 

    return s.str(); 
} 

Еще один момент: возможно, было бы правильно специализировать эту функцию для строк и процитировать их, потому что если строка в векторе начинается или заканчивается ,, было бы трудно понять, сколько строк было напечатано.

template <> 
std::string vectorToString<std::string>(const std::vector<std::string>& vec) { 
    if (vec.empty()) { 
     return "[]"; 
    } 
    std::ostringstream s; 
    s << "[" << vec.front(); 

    for (auto i = vec.begin() + 1, e = vec.end(); i != e; i++) 
    { 
     s << ", \"" << *i << "\""; 
    } 
    s << "]"; 

    return s.str(); 
} 
+0

Но что, если строки элементов содержат кавычки? Генерация CSV немного сложнее, и нужно использовать существующую библиотеку. –

1

Если вы работаете на C++ 11, вы можете использовать эту простую версию:

#include <sstream> 
#include <algorithm> 

using namespace std; 

template<typename T> 
string format(vector<T> const& v) 
{ 
    if (v.empty()) return "[]"; 
    ostringstream ss; 
    ss << "[" << v[0]; 
    for_each(begin(v) + 1, end(v), [&ss] (T const& s) { ss << ", " << s; }); 
    ss << "]"; 
    return ss.str(); 
} 

Если вы хотите сделать его общим для других типов коллекций (не только vector) или даже для поддиапазонов из коллекции, вы можете обобщить это так:

#include <sstream> 
#include <algorithm> 

using namespace std; 

template<typename It> 
string format(It b, It e) 
{ 
    if (b == e) return "[]"; 
    ostringstream ss; 
    ss << "[" << *b; 
    for_each(++b, e, [&ss] (decltype(*b)& s) { ss << ", " << s; }); 
    ss << "]"; 
    return ss.str(); 
} 

template<typename C> 
string format(C const& c) 
{ 
    return format(begin(c), end(c)); 
} 

int main() 
{ 
    vector<int> v = { 4, 5, 5, 8 }; 
    cout << format(v) << endl; 
    return 0; 
} 
0

Использования алгоритмы, которые обычно упрощают код (не уверен, что если в этом случае, но добавил, ради завершения):

template <typename T> 
std::string toString(std::vector<T> const & v) { 
    if (v.empty()) 
     return "[]"; 
    typename std::vector<T>::const_iterator last = std::prev(v.end()); 
    std::ostringstream st; 
    st << "[ "; 
    std::copy(v.begin(), last, std::ostream_iterator<T>(st,", ")); 
    st << *last << " ]"; 
    return st.str(); 
} 
Смежные вопросы