2015-09-16 2 views
3

Можно ли настроить общий C++ метод stringification:дословное stringify

template<typename T> 
std::string Stringify(T const &value) 
{ 
    std::stringstream ss; 
    ss << value; 
    return ss.str(); 
} 

так, что фактическое значение будет распечатано и не укороченную или научной нотации представление значения, например:

std::cout << Stringify(std::numeric_limits<float>::max()) << std::endl; 

не должен печатать 3.40282e+38 но 3'402'82... (я просто не упоминая остальные цифры, я не имею в виду, что точки должны быть напечатаны)

+1

use 'std :: fixed' – Sneftel

+0

Вы ищете' setprecision'? @Sneftel Это не обрабатывается, например, 0,0000001. –

+0

@ T.C. Моя первоначальная мысль заключалась в том, чтобы использовать его, но тогда проблема «setprecision» на что? Я имею в виду, что это должно быть динамическим и самонастраивающимся. –

ответ

4

Да, добавьте манипулятор (ы), который вы хотите к сигнатуре функции, и переместите их в поток.

template<typename T, typename Manip> 
std::string Stringify(T const &value, Manip manip) 
{ 
    std::stringstream ss; 
    ss << manip << value; 
    return ss.str(); 
} 

С образцом кода;

int main() 
{ 
    using namespace std; 
    // The precision here is set to be sufficient to print the test platform 
    cout << Stringify(numeric_limits<float>::max(), setprecision(50)) << endl; 
}  

Я полагаю, что более чем один манипулятор будет использоваться. С этой целью можно добавить функциональные перегрузки для необходимого количества манипуляторов или использовать (с C++ 11) вариативные шаблоны и совершенную пересылку.

template <typename Stream> 
Stream& AddManip(Stream& str) 
{ 
    // end the recursion 
    return str; 
} 

template <typename Stream, typename Head, typename... Tails> 
Stream& AddManip(Stream& str, Head&& head, Tails&&... tails) 
{ 
    // add the head manipulator and forward the rest 
    str << std::forward<Head>(head); 
    return AddManip(str, std::forward<Tails>(tails)...); 
} 

template<typename T, typename... Manip> 
std::string Stringify(T const &value, Manip&&... manip) 
{ 
    std::stringstream ss; 
    // add the manipulators to the stream 
    AddManip(ss, std::forward<Manip>(manip)...); 
    ss << value; 
    return ss.str(); 
} 

int main() 
{ 
    using namespace std; 
    cout << Stringify(numeric_limits<int>::max(), setprecision(40), std::hex) << endl; 
}  
1

Я знаю, что макросы являются злыми, но я сделал одно или два исключения в своих работах. Одним из них является this macro:

#include <sstream> 

#define SSTR(x) static_cast< std::ostringstream & >(\ 
     (std::ostringstream() << std::dec << x)).str() 

Detailed explanation available.

Один Достоинства этой конструкции является то, что манипуляторы могут быть легко встраиваются:

std::string str = SSTR("numeric_limits<float>::max is: " 
         << setprecision(50) 
         << numeric_limits<float>::max() 
         ); 

Другого Достоинством является то, что это компактное и довольно C++ 98.

Недостатком является то, что это макрос. ;-)

+0

Интересно, что это [быстрее] (http://coliru.stacked-crooked.com/a/07ba2fc476ff23d5), чем популярный метод, который я упоминаю в вопросе. Альтернативы C++ 11 [быстрее] (http://stackoverflow.com/q/23437778/2567683). Выход остается тем же, и я все равно не могу автоматически настроить точность таким образом. Я также добавил +1 к связанному ответу, потому что мне нравится блог –

+0

@NikosAthanasiou: У меня было подозрение, что компилятор мог бы немного оптимизировать вокруг временного объекта 'ostringstream', но никогда не потрудился фактически сравнить его. (Мое основное использование для 'SSTR()' - обманывает сообщения об исключениях, и в этом случае производительность в любом случае является вторичной.) Что касается автоматической точности, вы можете * добавить * setprecision' в макрос ... но в любом случае, спасибо за отзыв! – DevSolar

+1

@NikosAthanasiou: Я позволил добавить свой тест на свою домашнюю страницу. – DevSolar