Форум программистов, компьютерный форум, киберфорум
C++
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.62/13: Рейтинг темы: голосов - 13, средняя оценка - 4.62
143 / 122 / 21
Регистрация: 13.11.2012
Сообщений: 1,564
1

Перенаправление указателя при перегрузке оператора в variadic template

18.04.2015, 16:19. Показов 2351. Ответов 35
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Есть вот такой вот код (сделан в vs2014):
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#include "stdafx.h"
#include <iostream>
#include <conio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include "windows.h"
#include "windowsx.h"
 
using namespace std;
 
int Cur = 0;
 
struct var
{
    int ps; // pointer size
    union
    {
        bool b;
        int i;
        PVOID vp;
        char *pc;
        void *pv;
        int *pi;
        double *pd;
        operator bool & ()
        {
            cout << "### Bool overload operator" << endl;
            return b;
        }
        operator int & ()
        {
            cout << "### Int overload operator" << endl;
            return i;
        }
        operator int * ()
        {
            cout << "### POINTER Int overload operator" << endl;
            return pi;
        }
        operator double * ()
        {
            cout << "### POINTER Double overload operator" << endl;
            return pd;
        }
        operator double & ()
        {
            cout << "### Double overload operator" << endl;
            return pd[0]; // вот тут вопрос
        }
        operator PVOID & ()
        {
            cout << "### PVOID overload operator" << endl;
            return vp;
        }
        operator char * ()
        {
            cout << "### Char[] overload operator" << endl;
            return pc;
        }
        operator void * ()
        {
            cout << "### Void[] overload operator" << endl;
            return pv;
        }
    }d;
};
var **v;
 
template<typename Result, typename... Args>
void call(void * fun, Result& r, Args ... args)
{
    using func_type = Result(_cdecl *)(Args...); // прототип функции
    r = ((func_type)fun) (args...); // вызов функции
}
 
int SomeFunc2();
 
int _tmain(int argc, _TCHAR* argv[])
{
    if(SomeFunc2()==0)
        cout << "End Programm" << endl;
    _getch();
    return 0;
}
 
int SomeFunc2()
{
    int res = 0;
    int b = 2;
    v = new var*[b];//динамическая матрица
    v[0] = new var[10];
    v[1] = new var[6];
    v[0][0].d.i = 10;
    v[0][1].d.pc = new char[100];
    v[0][2].d.pc = new char[100];
    v[0][3].d.vp = NULL;
    v[0][4].d.vp = NULL;
    v[0][5].d.i = NULL;
    v[0][6].d.i = 100;
    v[0][7].d.pc = new char[100];
    v[0][8].d.i = 99;
    v[0][9].d.i = 10;
    //
    v[1][0].d.i = 6;
    v[1][1].d.i = NULL;
    v[1][2].d.pd = new double[10];
    v[1][3].d.pc = new char[100];
    v[1][4].d.i = 99;
    v[1][5].d.i = 10;
    //
    strcpy_s(v[0][1].d.pc, v[0][8].d.i, "msvcr120.dll");
    //
    for (int i = 0; i < 10; i++)
    {
        v[1][2].d.pd[i] = NULL;
    }
    strcpy_s(v[1][3].d.pc, v[1][4].d.i, "123.32");
    // test call with pd[0]
    v[1][2].d.pd[0] = atof(v[1][3].d.pc);
    cout << "Test atof result: " << v[1][2].d.pd[0] << endl;
    v[1][2].d.pd[0] = 0;
    //
    cout << "Library Name: " << v[0][1].d.pc << endl;
    int go = 0;
    v[0][3].d.vp = GetModuleHandleA(v[0][1].d);
    if (!v[0][3].d.vp)
    {
        cout << "Library -NOT- found, try load..." << endl;
        v[0][3].d.vp = LoadLibraryA(v[0][1].d);
        if (!v[0][3].d.vp)
            cout << "Library -NOT- loaded" << endl;
        else
        {
            cout << "Library loaded" << endl;
            go = 2;
        }
    }
    else
    {
        cout << "Library found" << endl;
        go = 1;
    }
    if (go != 0)
    {
        strcpy_s(v[0][2].d.pc, v[0][8].d.i, "atof");//_itoa_s
        cout << "Function Name: " << v[0][2].d.pc << endl;
        v[0][4].d.vp = GetProcAddress((HMODULE)v[0][3].d.vp, v[0][2].d.pc);
        if (!v[0][4].d.vp)
            cout << "Function -NOT- found" << endl;
        else
        {
            cout << "Function found, try call..." << endl;
            //call(v[0][4].d.vp, v[1][1].d, v[1][2].d, v[1][3].d, v[1][4].d, v[1][5].d);
            //call(v[0][4].d.vp, v[1][2].d.pi[0], v[1][3].d);
            //call(v[0][4].d.vp, v[1][2].d, v[1][3].d);
            //v[1][1].d.i = atoi(v[1][3].d.pc);
            Cur = 0;
            //v[1][2].d.pd[Cur] = atof(v[1][3].d.pc); // double
            //call(v[0][4].d.vp, v[1][2].d.pd[Cur], v[1][3].d);
            call(v[0][4].d.vp, v[1][2].d, v[1][3].d);
            if (v[1][2].d.pd[Cur] == NULL)
                cout << "Failed result, error: " << endl;
            else
            {
                //char fStr[100] = "";
                //sprintf_s(fStr, sizeof(fStr), "%f", v[1][2].d.pd[Cur]);
                cout << "Returned DOUBLE PTR[" << Cur << "]: " << v[1][2].d.pd[Cur] << endl;
            }
        }
        if (go == 2)
        {
            FreeLibrary((HMODULE)v[0][3].d.vp);
            cout << "Library cleaned" << endl;
        }
    }
    delete[]v[0][7].d.pc;
    delete[]v[0][2].d.pc;
    delete[]v[0][1].d.pc;
    delete[]v[0];
    delete[]v[1][3].d.pc;
    delete[]v[1][2].d.pd;
    delete[]v[1];
    delete[]v;
    return res;
}
Я не хочу вводить в вложенный юнион перменную double, вместо этого хочу чтоб нужная переменная вызывалась из указателя.

Как видится всё это... Вот это должно по сути сработать... (пока что статически написан "0", в будущем конешно хотелось бы тоже поправить, чтоб можно было изменить, для этого int Cur хотел использовать)
C++
1
2
3
4
5
operator double & ()
        {
            cout << "### Double overload operator" << endl;
            return pd[0]; // вот тут вопрос
        }
При выполении программы правильно работает только тест, где явно указано где что брать:
C++
1
v[1][2].d.pd[0] = atof(v[1][3].d.pc);
Потом уже при "не явном вызове" уже происходит ошибка, и получается что перегруженный оператор не срабатывает.
C++
1
call(v[0][4].d.vp, v[1][2].d, v[1][3].d);
Я так понимаю что шаблон всё равно ссылается на адрес v[1][2].d, а ведь я предполагал, что перегруженный оператор должен перенаправить адрес в указатель pd[0].

И ещё, смежный вопрос, как в самом шаблоне проверить какой тип требуется и адрес.
Т.е. хотелось бы чтоб в шаблоне можно было тоже следить за поведением переменных.
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
18.04.2015, 16:19
Ответы с готовыми решениями:

Передача в метод по перегрузке оператора указателя на объект
У нас есть массив указателей на базовый класс STRING **ptr = new STRING* ; for (int i = 0;...

Ошибка при перегрузке оператора ==
У меня компилятор выдает ошибку error LNK2019: ссылка на неразрешенный внешний символ &quot;bool __cdecl...

Ошибка при перегрузке оператора <<
class Predmet { private: int id; string name; public: Predmet() {}; Predmet(string name,...

Ошибка при перегрузке оператора >>
Приветствую. Есть 2 класса: enum Color { white = 1, red, green, blue, yellow }; class Shape {...

35
18844 / 9843 / 2408
Регистрация: 30.01.2014
Сообщений: 17,284
23.04.2015, 18:06 21
Author24 — интернет-сервис помощи студентам
Цитата Сообщение от Izual Посмотреть сообщение
Вот этот статический метод совсем не катит
Да я понимаю, что не катит. Это демонстрация того почему не работает и что сделать, чтобы "работало".

Цитата Сообщение от Izual Посмотреть сообщение
Но ведь третьим аргументом, он же указатель на char понимает. С чего он его понимает, если написан точно так же анонимный юнион?..
Как ты определил, что он именно "понимает"? Покажи код, о котором ты говоришь, чтобы был предметный разговор.

Знаешь, чтобы прояснить ситуацию, тебе надо задать другие вопросы. Например, тебе наверняка было бы полезно узнать как посмотреть какие именно типы попали в шаблон, чтобы разбираться по факту увиденного. а не по факту догадок. Интересно?
0
143 / 122 / 21
Регистрация: 13.11.2012
Сообщений: 1,564
23.04.2015, 18:26  [ТС] 22
Цитата Сообщение от DrOffset Посмотреть сообщение
Как ты определил, что он именно "понимает"? Покажи код, о котором ты говоришь, чтобы был предметный разговор.
Второй пример кода (какой там, 5 чтоли пост), где есть реальный double. Там работает функция atod, и аргументом так же посылается *char.

Цитата Сообщение от DrOffset Посмотреть сообщение
наверняка было бы полезно узнать как посмотреть какие именно типы попали в шаблон
Ага, и поэтому в первой теме в ПС было написанно это:
Цитата Сообщение от Izual Посмотреть сообщение
И ещё, смежный вопрос, как в самом шаблоне проверить какой тип требуется и адрес.
Т.е. хотелось бы чтоб в шаблоне можно было тоже следить за поведением переменных.
Цитата Сообщение от DrOffset Посмотреть сообщение
Интересно?
Очень! =)
0
18844 / 9843 / 2408
Регистрация: 30.01.2014
Сообщений: 17,284
23.04.2015, 19:48 23
Цитата Сообщение от Izual Посмотреть сообщение
Ага, и поэтому в первой теме в ПС было написанно это:
Эту формулировку можно воспринять по-разному. Она не столь однозначна, как тебе кажется. Ну да ладно, это не важно.
Вот код:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
template <typename T>
void print_t()
{
    printf("\n%s\n", __FUNCSIG__);
}
 
template <typename Result, typename... Args>
void call(void * fun, Result& r, Args ... args)
{
    print_t<decltype(call<Result, Args...>)>();
 
    using func_type = Result(_cdecl *)(Args...); // прототип функции
 
    print_t<func_type>();
 
    r = ((func_type)fun) (args...); // вызов функции
}
Строка, которую будет выводить функция print_t, будет содержать в том числе и типы параметров, которые попали в шаблон. Для твоего примера, например, будут такие строки
Это параметры самой функции call (выделил жирным куда смотреть)
void __cdecl print_t<void(void *,union var::<unnamed-type-d> &,union var::<unnamed-type-d>)>(void)
А это прототипа, к которому функция call приводит свой первый параметр:
void __cdecl print_t<unionvar::<unnamed-type-d>(__cdecl *)(union var::<unnamed-type-d>)>(void)
Как видно, получившаяся функция возвращает анонимный юнион и принимает такой же юнион в качестве параметра. Что в точности соответствует тому, что мы писали тебе ранее.

Цитата Сообщение от Izual Посмотреть сообщение
Там работает функция atod, и аргументом так же посылается *char.
Повезло. Бинарно указатель и твой юнион совместимы, поэтому сработало. Если же необходимо из указателя получить значение для передачи в функцию (твой первый вопрос), то совпадением по памяти уже не отделаешься.

Причем твой второй якобы работающий пример, все равно не работает, т.к. возвращает мусор, вместо 123.32. А все потому, что результат функции atof - double. Ты знаешь как возвращаются числа double в ассемблере?
Если проще будет понять на примере, то вот код.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
union test
{
    void * p;
    double d;
};
 
extern "C" double foo1();
extern "C" double foo2();
 
int main()
{
    double f1 = foo1();
    double f2 = foo2();
 
    printf("%lf %lf", f1, f2); //результаты отличаются!
}
Есть две функции, foo1() возвращает в результате обычный double. foo2() эмулирует то, что происходит у тебя.
Реализация функций такая:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
double f = 3.14;
// Функция возвращает double и компилятор знает об этом
extern "C" double foo1()
{
    return f;
}
 
extern "C" double foo2()
{
    // Насильно приведенная функция, теперь компилятор думает, что функция возвращает union test
    test (*fp)() = (test(*)())foo1;
    return fp().d;
}
Итак, результат первой функция напечатает 3.14. Вторая напечатает ноль или что-то невразумительное, не суть. Почему? Потому что ты ввел компилятор в заблуждение. Т.к. double и некий блок памяти 8 байт (наш юнион) возвращаются разными способами.
Для первой функции код, сгенерированный компилятором будет таким
Assembler
1
2
3
_foo1:
    fld QWORD PTR _f
    ret
И это правильный код. Компилятор знает, что функция возвращает double и генерирует оптимальный код для этого. Возвращается значение через стек FPU.
Для второй функции код такой:
Assembler
1
2
3
4
5
6
7
8
_foo2:
    sub esp, 12
    call    _foo1
    mov DWORD PTR [esp], eax
    mov DWORD PTR [esp+4], edx
    fld QWORD PTR [esp]
    add esp, 12
    ret
Сначала вызывается foo1. Пытаемся получить ее результат... во дела, да? Положили-то мы значение в стек FPU, а достаем откуда? Из пары EAX:EDX. Почему так произошло? Потому что компилятор ориентируется на типизацию, когда генерирует код. Объект 8 байт можно и нужно передать через регистры EAX:EDX, а вот double лучше передавать через FPU. Мы обманули его и получили некорректную программу. Если заменить вот этот блок
Assembler
1
2
3
    mov DWORD PTR [esp], eax
    mov DWORD PTR [esp+4], edx
    fld QWORD PTR [esp]
На
Assembler
1
2
    fstp  QWORD PTR [esp]
    fld  QWORD PTR [esp]
То все придет в норму. И числа показываться будут одинаковые.
В твоем коде картина та же.
0
143 / 122 / 21
Регистрация: 13.11.2012
Сообщений: 1,564
23.04.2015, 22:27  [ТС] 24
Цитата Сообщение от DrOffset Посмотреть сообщение
Повезло. Бинарно указатель и твой юнион совместимы, поэтому сработало. Если же необходимо из указателя получить значение для передачи в функцию (твой первый вопрос), то совпадением по памяти уже не отделаешься.
оО "совпадение по памяти" это как будто "иголка в стоге сена", адрес в 4 байтах, начиная с v[1][3].d, само значение фиг знает где...
Цитата Сообщение от DrOffset Посмотреть сообщение
все равно не работает, т.к. возвращает мусор
Да точно, хмм, странно, что то видимо я не посмотрел на это, увидел, вроде число и забил))

Откуда все эти ASM вообще ты берёш?.. и чё за FPU))

Добавлено через 10 минут
*Я так понимаю ты меня склоняеш к тому что ассемблерные вставки мне помогут... Ну пойду читать)
0
18844 / 9843 / 2408
Регистрация: 30.01.2014
Сообщений: 17,284
23.04.2015, 23:22 25
Лучший ответ Сообщение было отмечено Izual как решение

Решение

Цитата Сообщение от Izual Посмотреть сообщение
адрес в 4 байтах, начиная с v[1][3].d, само значение фиг знает где...
Юнион так устроен, что соответствует наиболее вместительному своему полю по размеру, адреса всех полей равны и равны адресу самой переменной юниона. Поэтому, если способ передачи параметра не различается (например как он различается в примере с double), то все равно какой был тип, главное, чтобы в первых его 4х байтах лежало то значение, которое ждет функция (в данном случае значение указателя). Проблемы начались бы, если бы у тебя был еще четвертый параметр, тогда в него попали бы остальные 4 байта твоего юниона (помним, что твой юнион 8 байт из-за double), а настоящий параметр затерялся. Я бы мог это продемонстрировать на примере кода, но все эти посты требуют большого количества времени, которого у меня нет. Если ты уделишь достаточное внимание обучению, то вскоре сам сможешь это делать без моей помощи.

Цитата Сообщение от Izual Посмотреть сообщение
Откуда все эти ASM вообще ты берёш?.. и чё за FPU))
Это дизассемблер примера на С++. Пример в том же посте.
FPU

Цитата Сообщение от Izual Посмотреть сообщение
Я так понимаю ты меня склоняеш к тому что ассемблерные вставки мне помогут... Ну пойду читать)
Я тебя склоняю к тому, что твою задачу можно решать, только если хорошо представлять что происходит на уровне инструкций процессора. В одном из прошлых постов я тебе давал ссылку на библиотеку, где с помощью ассемблера добились того, что ты хочешь. Я утверждаю, что тебе либо придется повторить их путь, либо бросить эту затею.
1
143 / 122 / 21
Регистрация: 13.11.2012
Сообщений: 1,564
23.04.2015, 23:31  [ТС] 26
Цитата Сообщение от DrOffset Посмотреть сообщение
где с помощью ассемблера добились того, что ты хочешь. Я утверждаю, что тебе либо придется повторить их путь, либо бросить эту затею.
Ну значит будем штрудировать. =)
Жалко конешно что "просто из перегруженного оператора" нельзя сделать то что я хочу, ну значит есть куда стремиться ещё. Гора, Магомет уже идёт)))
0
143 / 122 / 21
Регистрация: 13.11.2012
Сообщений: 1,564
26.04.2015, 16:43  [ТС] 27
DrOffset, да дизассембл интересная вещь... Жаль что твой пример, по крайней мере мне, сложно понять...
C++
1
2
test (*fp)() = (test(*)())foo1;
    return fp().d;
Это какой то лес =)

Собственно пока я тут копаюсь, накопалось оказывается, что без указания типа оператор double не срабатывает вообще. Т.е. на сколько я понял:
С таким подходом:
C++
1
call(v[0][4].d.vp, v[1][2].d, v[1][3].d);
Получается:
Assembler
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
0101B0BC  mov         eax,4  
0101B0C1  shl         eax,0  
0101B0C4  mov         ecx,10h  
0101B0C9  imul        edx,ecx,3  
0101B0CC  mov         ecx,dword ptr ds:[1021324h]  
0101B0D2  mov         eax,dword ptr [ecx+eax]  
0101B0D5  mov         ecx,dword ptr [eax+edx+0Ch]  
0101B0D9  push        ecx  
0101B0DA  mov         edx,dword ptr [eax+edx+8]  
0101B0DE  push        edx  
0101B0DF  mov         eax,4  
0101B0E4  shl         eax,0  
0101B0E7  mov         ecx,10h  
0101B0EC  shl         ecx,1  
0101B0EE  mov         edx,dword ptr ds:[1021324h]  
0101B0F4  mov         eax,dword ptr [edx+eax]  
0101B0F7  lea         ecx,[eax+ecx+8]  
0101B0FB  push        ecx  
0101B0FC  mov         edx,4  
0101B101  imul        eax,edx,0  
0101B104  mov         ecx,10h  
0101B109  shl         ecx,2  
0101B10C  mov         edx,dword ptr ds:[1021324h]  
0101B112  mov         eax,dword ptr [edx+eax]  
0101B115  mov         ecx,dword ptr [eax+ecx+8]  
0101B119  push        ecx  
0101B11A  call        call<var::<unnamed-type-d>,var::<unnamed-type-d> > (0101150Ah)  
0101B11F  add         esp,10h
А с таким:
C++
1
call(v[0][4].d.vp, (double)v[1][2].d, v[1][3].d);
Вот что:
Assembler
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
01145B7C  mov         eax,4  
01145B81  shl         eax,0  
01145B84  mov         ecx,10h  
01145B89  imul        edx,ecx,3  
01145B8C  mov         ecx,dword ptr ds:[1151324h]  
01145B92  mov         eax,dword ptr [ecx+eax]  
01145B95  mov         ecx,dword ptr [eax+edx+0Ch]  
01145B99  push        ecx  
01145B9A  mov         edx,dword ptr [eax+edx+8]  
01145B9E  push        edx  
01145B9F  mov         eax,4  
01145BA4  shl         eax,0  
01145BA7  mov         ecx,10h  
01145BAC  shl         ecx,1  
01145BAE  mov         edx,dword ptr ds:[1151324h]  
01145BB4  mov         eax,dword ptr [edx+eax]  
01145BB7  lea         ecx,[eax+ecx+8]  
01145BBB  call        var::<unnamed-type-d>::operator double & (0114150Fh)  
01145BC0  push        eax  
01145BC1  mov         ecx,4  
01145BC6  imul        edx,ecx,0  
01145BC9  mov         eax,10h  
01145BCE  shl         eax,2  
01145BD1  mov         ecx,dword ptr ds:[1151324h]  
01145BD7  mov         edx,dword ptr [ecx+edx]  
01145BDA  mov         eax,dword ptr [edx+eax+8]  
01145BDE  push        eax  
01145BDF  call        call<double,var::<unnamed-type-d> > (01141514h)  
01145BE4  add         esp,10h
Хотя почему они все dword я ещё не вкурил...

Добавлено через 13 минут
Ну и естественно из за этого сам шаблон уже по другому вопринимает данные. Без типа:
Assembler
1
2
3
4
5
6
7
8
00942FC0  call        __RTC_CheckEsp (0941370h)  
00942FC5  mov         dword ptr [ebp-0CCh],eax  
00942FCB  mov         dword ptr [ebp-0C8h],edx  
00942FD1  mov         edx,dword ptr [r]  
00942FD4  mov         eax,dword ptr [ebp-0CCh]  
00942FDA  mov         dword ptr [edx],eax  
00942FDC  mov         ecx,dword ptr [ebp-0C8h]  
00942FE2  mov         dword ptr [edx+4],ecx
С типом:
Assembler
1
2
3
00FF2FC0  call        __RTC_CheckEsp (0FF1370h)  
00FF2FC5  mov         edx,dword ptr [r]  
00FF2FC8  fstp        qword ptr [edx]
Как ты и сказал, похожая ситуация.

Добавлено через 7 минут
Цитата Сообщение от DrOffset Посмотреть сообщение
либо придется повторить их путь, либо бросить эту затею
Может есть обходной кстати вариант. Например меня одолевает мысль, что т.к. в принципе я имею в структуре уже известный тип, то можно было бы приводить аргументы в шаблоне. (static_cast'ом чтоль, это хоть и по коду займёт место, но зато это предполагаю будет эмулировать поведения для опр. типа, и тут уже я смогу и колдовать сразу с указателями, как в общем то я и хотел сделать с double)

Добавлено через 17 часов 12 минут
Цитата Сообщение от Nick Alte Посмотреть сообщение
Функция call. Она получает указатель на функцию, у которого выдрана вся информация об аргументах и возвращаемом значении.
Оказалось что прототип функции в шаблоне действительно себя странно ведёт.
C++
1
using func_type = Result(_cdecl *)(Args...); // прототип функции
Заменив Result (т.е. тип union) на double получил в дизассембле qword...
Лан, ушёл дальше ковыряться)
0
143 / 122 / 21
Регистрация: 13.11.2012
Сообщений: 1,564
28.04.2015, 21:39  [ТС] 28
Перегруженный оператор uniona не дал в итоге мне возможность возвращять разные типы значений.

Может ли функция вернуть разный тип? Читал про перегрузку функций и шаблоны, но ни то ни другое пока не нашёл как применить в виду следующих причин:
1. Перегруженная функция обязана иметь разные типы или кол-во аргументов. А у меня аргумент всегда один (структура).
2. Шаблонная функция требует статически написать тип, например:
C++
1
user_function<int>(3);
Либо иметь статический тип возвращяемого параметра, например:
C++
1
int a = user_f(3);
У меня же из функции должен выйти тип, соотв. например числу.
Подразумевается:
C++
1
2
3
4
5
6
7
8
9
10
11
template <typename T1>
T GetVar(var v)
{
    int type = v.t;
    bool b = v.d.b;
    int i = v.d.i;
    if(type == 0)
        return b;
    else
        return i;
}
Только тут будет нужно опять же написать в угловых скобках тип, а мне надо без этого.

Использовать хочу для вызова своей функции:
C++
1
call(v[0][4].d.vp, GetVar(v[1][2]), GetVar(v[1][3]));
Где call ->
C++
1
2
3
template<typename Result, typename... Args>
void call(void * fun, Result& r, Args ... args)
...
0
What a waste!
1608 / 1300 / 180
Регистрация: 21.04.2012
Сообщений: 2,729
28.04.2015, 22:27 29
Цитата Сообщение от Izual Посмотреть сообщение
У меня же из функции должен выйти тип, соотв. например числу.
Если "соответствие числу" определяется на этапе исполнения программы, то шаблоны и перегрузка не помогут, т.к. это статический полиморфизм, т.е. здесь например
Цитата Сообщение от Izual Посмотреть сообщение
C++
1
2
3
4
5
6
7
8
9
10
11
template <typename T1>
T GetVar(var v)
{
* * int type = v.t;
* * bool b = v.d.b;
* * int i = v.d.i;
* * if(type == 0)
* * * * return b;
* * else
* * * * return i;
}
тип T должен быть определён до исполнения программы.
0
143 / 122 / 21
Регистрация: 13.11.2012
Сообщений: 1,564
28.04.2015, 22:34  [ТС] 30
Цитата Сообщение от gray_fox Посмотреть сообщение
Если "соответствие числу" определяется на этапе исполнения программы
Надо в runtime...

Добавлено через 1 минуту
Цитата Сообщение от gray_fox Посмотреть сообщение
шаблоны и перегрузка не помогут
А что может помочь? (я конешно уже получил вариант с dyncall от offseta, но сторонняя библиотека..)
0
What a waste!
1608 / 1300 / 180
Регистрация: 21.04.2012
Сообщений: 2,729
28.04.2015, 22:44 31
Цитата Сообщение от Izual Посмотреть сообщение
Надо в runtime...
Сотню раз наверное уже писали, но в рамках языка С++ этого неосуществимо.

Добавлено через 3 минуты
Цитата Сообщение от Izual Посмотреть сообщение
А что может помочь? (я конешно уже получил вариант с dyncall от offseta, но сторонняя библиотека..)
Динамический полиморфизм (т.е. типы определяются в runtime), в С++ это в любом случае сводиться к иерархии классов с виртуальными методами.

Добавлено через 4 минуты
Либо некий обобщённый handle на ресурс и много switch-ей и cast-ов везде, где нужно знать тип объекта.
0
143 / 122 / 21
Регистрация: 13.11.2012
Сообщений: 1,564
28.04.2015, 22:58  [ТС] 32
Цитата Сообщение от gray_fox Посмотреть сообщение
обобщённый handle на ресурс и много switch-ей и cast-ов
Хотя бы так, но в рамках того что функция может требовать разное кол-во членов, хотелось бы чтоб был некий обобщённый вариант возврата.
типа:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int CallFunction(var *&fvar)
{
    int res = 1;
    char ftps[7][20] = {"bool","int","double","PVOID","char *","void *","int *"};
    if (fvar[0].d.i <= 0)
        return 0;
    switch (fvar[0].d.i)
    {
    case 3:
        cout << "### 3 args entering" << endl;
        call(fvar[1].d.vp, GetVar(fvar[2]));
        break;
    case 4:
        cout << "### 4 args entering" << endl;
        call(fvar[1].d.vp, GetVar(fvar[2]), GetVar(fvar[3]));
        break;
    default:
        return -1;
    }
}
Не проблема написать статически тут ~9 case для 1-9 агрументов.
Если можно было бы создать одну функцию (с ~20 case под кол-во типов), в чём собственно и вопрос)
0
143 / 122 / 21
Регистрация: 13.11.2012
Сообщений: 1,564
01.05.2015, 08:11  [ТС] 33
Цитата Сообщение от DrOffset Посмотреть сообщение
double и некий блок памяти 8 байт (наш юнион) возвращаются разными способами.
Ты же наверно не случайно мне привёл этот пример... Хотелось бы пояснений..))
Я так предполагаю, что дело происходит так:
Ляляля, вызывается функция atod, наверно неважно как туда попали данные, сама функция сделает всё правильно не зависимо от того, union ли туда передали или нет и возвратит тоже правильно, но уже из возвращяемого значения (из стека наверно) будет произведена конвертация в тип union, а тут уже "как получится" (предполагаю что вернуло по инструкции long long(8 байт же), ведь для каждого типа свои блоки памяти для опр. перечней данных, ну типа где знак, где целая часть, где дробная и т.д.)

В общем, используя ассемблер можно ли подменить тип возврата? Или может можно извлечь "не правильно скомпанованные данные" и поменять что то(в каких то регистрах) местами по нужной конструкции double, и будет как надо?...
0
18844 / 9843 / 2408
Регистрация: 30.01.2014
Сообщений: 17,284
02.05.2015, 17:44 34
Izual, не очень понятно что ты хочешь.
Но сразу скажу что сделать нельзя. Нельзя динамически, имея только указатель на функцию, узнать каким именно образом она возвращает данные. Через регистры общего назначения, FPU или еще как. Это можно сделать, только заранее зная прототип этой функции и правильную конвенцию вызова. И это касается не только С++ .
Цитата Сообщение от Izual Посмотреть сообщение
В общем, используя ассемблер можно ли подменить тип возврата? Или может можно извлечь "не правильно скомпанованные данные" и поменять что то(в каких то регистрах) местами по нужной конструкции double, и будет как надо?...
Я так понимаю это вот к этому вопрос:
Цитата Сообщение от Izual Посмотреть сообщение
У меня же из функции должен выйти тип, соотв. например числу.
Если так, то в целом это можно сделать. Даже без ассемблера.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
template <typename ...Args>
variant<int, double, float, char> call(int retType, Args... args)
{
    switch(retType)
    {
    case 1:
         return call_impl<int>(args...); // ставится в соответствие статический тип возврата и число
         // call_impl имеет реализацию как в первом твоем посте (функция call)
    case 2:
         return call_impl<double>(args...);
    // и т.д.
    }
}
Вообще, вся эта твоя задача дробится на две отдельные, сложные задачи. Первая задача - написать вариантный тип. В принципе реализации такие уже есть. Но в целом можно конечно сделать и свой. Эта задача целиком и полностью решается в рамках языка С++. Вариантов решения есть два, полиморфная реализация и шаблонная реализация. Примеры: boost::any и boost::variant.
Вторая задача, еще более сложная. Нужно сделать так, чтобы на основе информации времени исполнения, сохраненной в нашем вариантном типе (это информация о том, какой там тип на самом деле), сгенерировался правильный вызов некой процедуры. От процедуры у нас есть только адрес, ну и конвенция вызова (если это вызовы win api, то она известна и едина для всех них). Вот это решить средствами С++ на 100% нельзя. И код, который будет осуществлять вызов нашей процедуры придется генерировать динамически прямо в памяти, а потом отдавать ему управление. Естественно, если процедура на самом деле имеет другие параметры или другую конвенцию вызова, мы, при таком подходе, становимся никак не защищены от падений и других спецэффектов. Т.е. все на наш страх и риск. Т.е. вторая задача потребует от тебя написать маленький компилятор внутри своей программы, который будет прямо в памяти делать код для вызова исходя из динамической информации о типе, сохраненном в variant.
Есть готовые реализации таких вещей, у некоторых компиляторов есть api для JIT генерации кода, есть еще вот такая библиотека. Но если ты все-таки собрался все-все делать сам, приготовься к тому, что изучать придется очень много, и поверхностным ознакомлением не обойтись.
0
143 / 122 / 21
Регистрация: 13.11.2012
Сообщений: 1,564
05.05.2015, 11:07  [ТС] 35
Цитата Сообщение от DrOffset Посмотреть сообщение
что ты хочешь
Хочу использовать функции из DLL'ок. Пока что все примеры с гугла провальны, все они требуют либо статически писать типы(к чему мы в общем то подошли) либо статически описывать прототипы функции, просто потому что из DLLки "нормальный" прототип не вытаскивается =(

Цитата Сообщение от DrOffset Посмотреть сообщение
Через регистры общего назначения, FPU или еще как.
Я потому и спросил в предыдущем посте, можно ли выцедить данные из стека, которые возвращет функция.

Цитата Сообщение от DrOffset Посмотреть сообщение
variant<int, double, float, char> call
Цитата Сообщение от DrOffset Посмотреть сообщение
return call_impl<int>
Опять же статически всё, тоже самое что я буду в скобках писать тип для подачи в ф. call

Цитата Сообщение от DrOffset Посмотреть сообщение
полиморфная реализация и шаблонная реализация
Полиморфизм даёт dynamic_cast, но он один фиг мне вернёт тип класса, а не базовый(char,int,float,double).
Да и виртуальная функция не подойдёт, т.к. мне надо разный тип получать, а вирт. функции возвращяют всё по одному прототипу.
Шаблон дал лиш часть, как видно, но не всё что надо... Сам же знаеш)

Цитата Сообщение от DrOffset Посмотреть сообщение
Вот это решить средствами С++ на 100% нельзя
Потому топик и висит, что ответа "как сделать чтоб работало" ещё небыло, (кроме dyncall, но как то сторонней библиотекой неизвестной пользоваться не хочется, да и честно говоря по ней инфы мало), даже блин вектора движения ещё не предложили. =(

Цитата Сообщение от DrOffset Посмотреть сообщение
при таком подходе, становимся никак не защищены от падений
Ну с таким же успехом можно сказать, что может вырубиться электричество)) Типы то есть, только они в string виде, а string в тип не конвертится)

Цитата Сообщение от DrOffset Посмотреть сообщение
маленький компилятор внутри своей программы
Есть пример? Или "чё почитать"?))

Цитата Сообщение от DrOffset Посмотреть сообщение
что изучать придется очень много
Не проблема, если это стоит того...

Добавлено через 1 час 55 минут
Сижу пока асм изучаю, пытаюсь свою теорию по поводу стэка подтвердить...
Нашёл вот что:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
int MySquare(int n)
{
  return n*n;
}  
   push bp                   ;Сохранить регистр указателя базы
   mov bp, sp                ;Адресовать стек регистром bp
   mov bx, word ptr [bp+4]   ;Записать int n в bx
   mov ax, bx                ;Переслать bx в ax
   imul bx                   ;Умножить ax на bx
   jmp short @2@58           ;Перейти к следующей команде
@2@58: 
   pop bp                    ;Восстановить регистр bp
   ret                       ; вернуться в место вызова
И вуаля, оптимизация:
C++
1
2
3
4
5
6
7
8
9
10
11
#pragma warn -rvl
int MySquare (int n)
{ 
 
/*return n*n; */  
 asm {
         mov ax, word ptr n
         imul bx
        }
}      
#pragma warn .rvl
Если уж тут return'a нет, и данные непосредственно из стэка забираются, то почему бы так же напрямую из стека не забрать не корректное возвратное значение функции?... (или union возврат пилится на столько, что извлекать из стека нечего?)
0
18844 / 9843 / 2408
Регистрация: 30.01.2014
Сообщений: 17,284
05.05.2015, 13:33 36
Цитата Сообщение от Izual Посмотреть сообщение
Если уж тут return'a нет, и данные непосредственно из стэка забираются, то почему бы так же напрямую из стека не забрать не корректное возвратное значение функции?
Во-первых не из стека, а из регистра ax. Команда imul сохраняет результат в ax, и, согласно calling convention для x86, целые числа как раз возвращаются через ax. Т.е. фактически return здесь есть.

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

Цитата Сообщение от Izual Посмотреть сообщение
Есть пример? Или "чё почитать"?))
Ключевые слова для поиска "generating function calls dynamically".

Цитата Сообщение от Izual Посмотреть сообщение
Потому топик и висит, что ответа "как сделать чтоб работало" ещё небыло, (кроме dyncall, но как то сторонней библиотекой неизвестной пользоваться не хочется, да и честно говоря по ней инфы мало), даже блин вектора движения ещё не предложили. =(
На данном этапе я сомневаюсь, что кто-то сможет предложить то, что тебе подойдет сразу. Я тебе предлагаю учиться. В данной ситуации, на мой взгляд, это лучше всего. Чтобы постичь сложные технические решения - надо учиться. Так уж вышло, что тема, которую ты затронул, не относится к разряду тривиальных. И по еще одному совпадению она не относится к разряду жизненно необходимых индустрии (проще говоря, это практически никому не нужно). Поэтому с одной стороны, информации очень мало в свободном доступе, т.к. этими вопросами занимаются единицы, с другой стороны, решения, которые уже есть, требуют высокой квалификации, чтобы их понять.

Цитата Сообщение от Izual Посмотреть сообщение
Полиморфизм даёт dynamic_cast, но он один фиг мне вернёт тип класса, а не базовый(char,int,float,double).
Да и виртуальная функция не подойдёт, т.к. мне надо разный тип получать, а вирт. функции возвращяют всё по одному прототипу.
Нужно под другим углом смотреть на задачу. Ты смотришь не под тем. То, что возвращает виртуальная функция в данной задаче вообще не интересно. Тут другие ее особенности используются. В любом случае ради примера писать тебе вариантный тип я не стану. Это трудоемко, и я сомневаюсь, что ты сможешь оценить мои старания. Т.к. сразу вникнуть в сложный код не получится, а долго разбираться в чужом коде ты не любишь Уж не обижайся.
0
05.05.2015, 13:33
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
05.05.2015, 13:33
Помогаю со студенческими работами здесь

Ошибки при перегрузке оператора <<
dc.cpp не видит private поля из dc.h dc.h #pragma once #include &lt;cmath&gt; class dc {

Предупреждение при перегрузке оператора
Есть вот такой код для созданный для обучения #include &lt;iostream&gt; using namespace std; ...

Ошибка при перегрузке оператора +
Имеется класс, который представляет из себя строку и количество символов в ней. Задача -...

Variadic template
Добрый день, господа. Будьте добры, помогите кто может. Есть у меня шаблонный класс ...


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

Или воспользуйтесь поиском по форуму:
36
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru