116 / 106 / 51
Регистрация: 29.03.2016
Сообщений: 480
1

Шаблонная функция вывода переменной в строку

17.04.2016, 13:20. Показов 2084. Ответов 15
Метки нет (Все метки)

можно ли оживить конструкцию:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <windows.h>
#include <iostream>
#include <typeinfo>
 
using namespace std;
 
template<typename T>
char* toACHARS(T t)
{
    LPCSTR tcode = typeid(t).name();
    char* b;
    switch(tcode[0])
    {
        case 's': case 'i': case 'l': case 'x':
        {
            sprintf(b, "%d", t);
        }
        break;
        case 't': case 'j': case 'm': case 'y':
        {
            sprintf(b, "%u", t);
        }
        break;
        case 'f': case 'd': case 'e':
        {
            sprintf(b, "%f", t);
        }
        break;
    }
    return b;
}
 
int main()
{
    int x = 1512;
    cout << toACHARS(x) << endl;
    return 0;
}


тут, видимо проблема вызвана функцией sprintf(). она не желает получать переменную заранее не определенного типа. могу переписать шаблонную функцию:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
template<typename T1>
char* toACHARS(T1 t)
{
    LPCSTR tcode = typeid(t).name();
    char size = 0;
    char* b;
    char znak = '+';
    switch(tcode[0])
    {
        case 's': case 't': case 'i': case 'j': case 'l': case 'm': case 'x': case 'y':
        {
            if (t < 0) 
            {
                znak = '-';
                t *= -1;
            }
            
            for (T1 i = t; i > 0; i /= 10) size++;
            if (znak == '-') 
            {
                b = new char[size + 2];
                b[0] = znak;
                b[size + 1] = 0;
                for (T1 i = t; i > 0; i /= 10)
                {
                    size--;
                    b[size + 1] = (i - ((i / 10) * 10))  + 48;
                }
            }
            else
            {
                b = new char[size + 1];
                b[size] = 0;
                for (T1 i = t; i > 0; i /= 10)
                {
                    size--;
                    b[size] = (i - ((i / 10) * 10))  + 48;
                }
            }
        }
        break;
        case 'f': case 'd': case 'e':
        {
            // долгие-нудные преобразования по IEEE 754
        }
        break;
    }
    return b;
}

но очень не хочется сталкиваться с геморроем IEEE 754
и несколько перегруженных функций делать тоже не хочется (хотя гораздо быстрее и проще)

есть ли шанс?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
17.04.2016, 13:20
Ответы с готовыми решениями:

Шаблонная функция вывода для любого stl контейнера
Шаблонная функция вывода для любого STL-контейнера, где в качестве параметра должен быть тип...

Функция для вывода в строку
Есть таблица Заселение Создать запрос количества клиентов за год+вывести номера гостиницы которые...

Вывод переменной из php в строку ввода/вывода на форме Html
Добрый день! Столкнулся с такой проблемой, не знаю как вывести переменную из php в строку...

Шаблонная функция
Помогите понять почему когда вызываешь функцию уже для конкретного типа (int,char*,double и...

15
Модератор
Эксперт С++
12626 / 10124 / 6097
Регистрация: 18.12.2011
Сообщений: 27,157
17.04.2016, 13:46 2
Лучший ответ Сообщение было отмечено Serg_o_Grey как решение

Решение

Что-то я не пойму, зачем городить шаблонную функцию, если есть потоковый вывод в строку
C++
1
2
3
4
5
#include <sstream>
...
   ostringstream ss;
   ss<<t;
   string result=ss.str();
1
116 / 106 / 51
Регистрация: 29.03.2016
Сообщений: 480
17.04.2016, 14:03  [ТС] 3
Цитата Сообщение от zss Посмотреть сообщение
зачем городить шаблонную функцию, если есть потоковый вывод в строку
да, незачем
спасибо
0
16466 / 8966 / 2198
Регистрация: 30.01.2014
Сообщений: 15,567
17.04.2016, 14:06 4
Цитата Сообщение от Serg_o_Grey Посмотреть сообщение
видимо проблема вызвана функцией sprintf()
Проблема здесь в том, что ты память под строку, которую отдаешь sprintf для записи, не выделил. У тебя просто указатель, причем мусорный.
Цитата Сообщение от Serg_o_Grey Посмотреть сообщение
C++
1
char* b;
UB же.

Чтобы правильно выделять память под строковое представление числа можно определять количество десятичных разрядов в числе с помощью std::numeric_limits<T>::digits10 + 2-4 сивола под +,-,. и \0.
Цитата Сообщение от Serg_o_Grey Посмотреть сообщение
C++
1
char* toACHARS(T t)
Указатель на память локального массива возвращать тоже нельзя, а динамически распределенная память будет нуждаться во внешнем удалении. Используй std::string.

А вообще конечно этот код разве что только для экспериментов сгодится.
1
116 / 106 / 51
Регистрация: 29.03.2016
Сообщений: 480
17.04.2016, 14:17  [ТС] 5
Цитата Сообщение от DrOffset Посмотреть сообщение
Проблема здесь в том, что ты память под строку, которую отдаешь sprintf для записи, не выделил. У тебя просто указатель, причем мусорный.
об этом я тоже думал, поэтому выделял и все равно не помогло.

Добавлено через 1 минуту
Цитата Сообщение от DrOffset Посмотреть сообщение
А вообще конечно этот код разве что только для экспериментов сгодится.
это и были эксперименты
0
16466 / 8966 / 2198
Регистрация: 30.01.2014
Сообщений: 15,567
17.04.2016, 14:19 6
Цитата Сообщение от Serg_o_Grey Посмотреть сообщение
об этом я тоже думал,
Очевидно как-то не так выделял.
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <windows.h>
#include <iostream>
#include <string>
#include <limits>
#include <typeinfo>
 
using namespace std;
 
template<typename T>
std::string toACHARS(T t)
{
    std::type_info const & ti = typeid(t);
    
    LPCSTR tcode = ti.name();
    char b[std::numeric_limits<T>::digits10 + 4];
    switch(tcode[0])
    {
    case 'i': case 's':
        {
            sprintf(b, "%d", t);
        }
        break;
    case 'u':
        {
            sprintf(b, "%u", t);
        }
        break;
    case 'f': case 'd': case 'e':
        {
            sprintf(b, "%f", t);
        }
        break;
    case 'c':
        {
            sprintf(b, "%c", t);
        }
        break;
    }
    return b;
}
 
int main()
{
    cout << toACHARS(1234) << endl;
    cout << toACHARS(-1u) << endl;
    cout << toACHARS(2.456) << endl;
    cout << toACHARS(short(2)) << endl;
    cout << toACHARS('D') << endl;
    return 0;
}

http://rextester.com/YNUV10755
1
116 / 106 / 51
Регистрация: 29.03.2016
Сообщений: 480
17.04.2016, 14:19  [ТС] 7
Цитата Сообщение от DrOffset Посмотреть сообщение
std::numeric_limits<T>::digits10
возьму на заметку
0
16466 / 8966 / 2198
Регистрация: 30.01.2014
Сообщений: 15,567
17.04.2016, 14:30 8
Serg_o_Grey, В том коде все равно не все гладко.
Нужно заменить, sprintf на snprintf для контроля выхода за границы, добавить default: (поведение по-умолчанию) в switch и для неучтенных типов. Еще нужно учитывать, что этот код непортируемый, т.к. завязан на реализацию type_info в Visual Studio. Проблемы при переходе на x64 тоже будут наблюдаться, т.к. в printf необходимо будет скорректировать параметры форматирования для некоторых типов, а этого сейчас нет. Правильная реализация разрастется очень сильно.
В общем, я тебе по технической части подсказал, но вообще лучше этот код не использовать.
1
116 / 106 / 51
Регистрация: 29.03.2016
Сообщений: 480
17.04.2016, 14:36  [ТС] 9
Цитата Сообщение от DrOffset Посмотреть сообщение
Указатель на память локального массива возвращать тоже нельзя
почему нельзя? кучу фрагментирую?
0
16466 / 8966 / 2198
Регистрация: 30.01.2014
Сообщений: 15,567
17.04.2016, 14:38 10
Цитата Сообщение от Serg_o_Grey Посмотреть сообщение
кучу фрагментирую?
Я про массив на стеке.
Ты же понимаешь, что он "помрет" по выходу из функции?
1
116 / 106 / 51
Регистрация: 29.03.2016
Сообщений: 480
17.04.2016, 14:57  [ТС] 11
помрет не массив а указатель на память, который я спас выведя его из функции.
единственный вопрос, не перезапишет ли какая-нибудь другая функция информацию (или часть информации) в этом массиве
0
16466 / 8966 / 2198
Регистрация: 30.01.2014
Сообщений: 15,567
17.04.2016, 15:03 12
Цитата Сообщение от Serg_o_Grey Посмотреть сообщение
помрет не массив а указатель на память
С точки зрения языка помрет именно массив.
Если, допустим, это массив каких-то объектов класса, то у них у всех будут вызваны деструкторы, а это формальная смерть объекта. У char конечно никаких деструкторов нет, но с точки зрения объектов они уже перестают существовать все равно. Другое дело, что память для объектов некоторое время еще будет доступна в нетронутом виде, пока кто-нибудь не воспользуется ей. Но обращаться к ней через указатель (или, допустим, ссылку), который ты "спас", ты не имеешь права.
1
116 / 106 / 51
Регистрация: 29.03.2016
Сообщений: 480
17.04.2016, 15:08  [ТС] 13
так что, мне в функцию указатель на внешний участок памяти передавать нужно, чтобы на этот участок информация записывалась?
0
16466 / 8966 / 2198
Регистрация: 30.01.2014
Сообщений: 15,567
17.04.2016, 15:26 14
Цитата Сообщение от Serg_o_Grey Посмотреть сообщение
так что, мне в функцию указатель на внешний участок памяти передавать нужно, чтобы на этот участок информация записывалась?
Да, это классический подход в С: передавать указатель на внешний буфер и его размер.
Но в целом конечно все зависит от ситуации. В некоторых случаях могут быть приемлемы и другие способы, например возвращать динамически аллоцированный буфер или использование статической переменной.
0
116 / 106 / 51
Регистрация: 29.03.2016
Сообщений: 480
17.04.2016, 16:21  [ТС] 15
на форуме видел уже кучу примеров, типа:
C++
1
2
3
4
5
6
7
string concat(string s1, string s2)
{
    string rez = s1 + s2;
    return rez;
}
...
string str = concat("sdf", "sdfsdhg");
так что получается, в последней строке происходит копирование значения из rez в str?

Добавлено через 4 минуты
теперь переучиваться нужно
DrOffset, спасибо за своевременную "затрещину"

Добавлено через 41 минуту
DrOffset, еще вопрос
я передаю в функцию "мусорный"указатель (char *msg). внутри функции определяю необходимый размер, выделяю память для этого указателя, записываю туда все что хотел и завершаю выполнение функции и работаю с полученным массивом

такой порядок допустим?

Добавлено через 4 минуты
а не, все разобрался. не допустим. стек ведь
0
16466 / 8966 / 2198
Регистрация: 30.01.2014
Сообщений: 15,567
17.04.2016, 17:26 16
Лучший ответ Сообщение было отмечено Serg_o_Grey как решение

Решение

Цитата Сообщение от Serg_o_Grey Посмотреть сообщение
так что получается, в последней строке происходит копирование значения из rez в str?
Да. Конструктор копии класса std::string следит за этим.
Массивы же по значению не копируются. Т.е. из функции можно вернуть только указатель\ссылку на массив, и, в случае если массив локальный, это приведет к некорректному доступу к уже "мертвой" памяти.

Для того, чтобы реализовать разные стратегии копирования используют владеющие классы (например std::string владеет свои внутренним буфером для строки и следит за тем, чтобы он корректно копировался) или какие-нибудь обертки. Например, для обычных массивов можно использовать обертку в виде структуры. Сейчас это есть в стандарте, называется std::array. С ним код выше мог бы выглядеть так:
C++
1
2
3
4
5
6
7
8
9
10
11
#include <array>
#include <limits>
 
template <typename T>
std::array<char, std::numeric_limits<T>::digits10 + 4> toACHARS(T value)
{
    std::array<char, std::numeric_limits<T>::digits10 + 4> buf = {};
    // что-то записываем в buf
 
    return buf;
}
Здесь из функции будет возвращена полная копия локальных данных. Следовательно все будет хорошо.
1
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
17.04.2016, 17:26
Помогаю со студенческими работами здесь

Шаблонная функция
Как &quot;научить&quot; шаблонную функцию отличать массив от контейнера, то есть если написать: template...

Шаблонная функция
Всем привет. Пытаюсь реализовать простенький парсер. Суть в том, что у меня есть ini файл с...

Шаблонная функция
Дорогие форумчане, нуждаюсь в вашей помощи: имеется несколько функций, с большим объемом кода....

Шаблонная функция
Учу c++, в книге приводится вот такой листинг примера работы шаблонной функции, однако он не...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
16
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2023, CyberForum.ru