PDA

Просмотр полной версии : [Урок] Перегрузка функций в Pawn (tagof)



Daniel_Cortez
08.05.2015, 20:57
WARNING:

В данной статье приводится уйма нестандартных решений.
Если вы новичок в Pawn или просто одержимы "чистотой" кода, рекомендую вам немедленно нажать Ctrl+W, Alt+F4 и для верности выполнить в командной строке "format C".
Дисклеймер: я не несу ответственности за то, что вы сделаете со своей системой с помощью вышеописанных инструкций.



Всем привет, с вами снова Daniel_Cortez (http://pro-pawn.ru/member.php?100-Daniel_Cortez).

Сегодня я опишу недавно открытый мной приём по перегрузке функций в Pawn.
Думаю, некоторые из вас видели раньше т.н. перегрузку функций в таких языках программирования, как C++:


#include <cstdio>

// выводит на экран целочисленное значение
void Print(int arg)
{
printf("int: %d\n", arg);
}

// выводит вещественное значение
void Print(double arg)
{
printf("float: %f\n", arg);
}

// выводит логическое значение
void Print(bool arg)
{
// у функции printf нет спецификатора "%b" для bool, поэтому придётся
// реализовать вывод логических значений другим способом
printf("bool: %s\n", (arg) ? ("true") : ("false"));
}


int main(int argc, char **argv)
{
Print(1);
Print(1.0);
Print(true);
return 0;
}

Обратите внимание: в коде приведены 3 функции с одинаковым именем "Print", которые отличаются лишь параметрами.
Это и называется перегрузкой функций - возможность использовать несколько одноимённых функций с разным количеством параметров или параметрами разного типа.

Если откомпилировать такую программу и запустить, она выведет на экран:


int: 1
float: 1.000000
bool: true


Почему я привожу пример на C++ ?
Да потому, что в Pawn всё не так просто - там нет нативной поддержки перегружаемых функций (так же, как и в C89, от которого и произошёл Pawn).
Тем не менее, можно имитировать эту возможность с помощью других штатных средств языка.

Итак, в Pawn мы не можем создавать функции с одинаковыми именами.
Но ведь мы можем сделать 3 функции с разными именами.
Затем добавим после них 4-ю, которая будет вызывать одну из первых трёх в зависимости от типа передаваемого параметра.


#include <a_samp>


// В Pawn фигурные скобки вокруг тела функции не обязательны,
// если оно состоит всего из 1 предложения.
stock PrintInt(i)
printf("int: %d", i);

stock PrintFloat(Float:f)
printf("float: %f", f);

stock PrintBool(bool:b)
printf("bool: %s", (b)?("true"):("false"));

// Основная функция.
// Фигурные скобки в типе параметра означают,
// что параметр может быть нескольких типов -
// в данном случае функция принимает параметры
// целочисленного типа (_), вещественные числа (Float)
// и логические значения (bool).
stock Print({_, Float, bool}:arg)
{
// Здесь функция будет вызывать PrintInt/PrintFloat/PrintBool.
}


// Здесь будем проверять работу Print(), по аналогии с примером на C++.
main()
{
print("--Function overloading emulation test--");
Print(1);
Print(1.0);
Print(true);
}

Следует заметить, что никаких типов данных в Pawn на самом деле нет: интерпретатор сам по себе поддерживает работу только с целыми числами.
К логическим переменным (bool) также применяются стандартные операции, применяемые к целым числам, а вещественные числа (Float) обрабатываются с помощью нативных функций, объявленных в float.inc.
Вместо типов компилятор использует теги - это и есть те самые "bool:", "Float:" и т.п. в объявлениях переменных, констант и функций.

Теперь сконцентрируем внимание на функции Print.
Как уже говорилось выше, она будет вызывать PrintInt/PrintFloat/PrintBool в зависимости от тега аргумента arg.
Но как именно мы будет определять тег аргумента?
Очень просто: для этого в Pawn есть оператор tagof, который определяет ID тега переменной, константы или функции.

Добавим в функцию Print ещё один параметр arg_type, который будет передаваться неявным образом.
И поскольку оператор tagof возвращает целочисленное значение, можно будет сделать вызовы PrintInt/PrintFloat/PrintBool из конструкции switch:


stock Print({_, Float, bool}:arg, arg_type=tagof(arg))
{
switch(arg_type)
{
case tagof(_:):
PrintInt(arg);
case tagof(Float:):
PrintFloat(arg);
case tagof(bool:):
PrintBool(arg);
}
}

Пробуем скомпилировать и напарываемся на кучу сообщений от компилятора:


test.pwn(16) : warning 220: expression with tag override must appear between parentheses
test.pwn(16) : error 020: invalid symbol name "_"
test.pwn(16) : error 029: invalid expression, assumed zero
test.pwn(18) : warning 217: loose indentation
test.pwn(18) : error 014: invalid statement; not in switch
test.pwn(18) : warning 215: expression has no effect
test.pwn(18) : error 001: expected token: ";", but found ":"
test.pwn(18) : error 029: invalid expression, assumed zero
test.pwn(18) : fatal error 107: too many error messages on one line

Compilation aborted.

Pawn compiler 3.10.20150531 Copyright (c) 1997-2006, ITB CompuPhase


6 Errors.

Всё дело в том, что в Pawn 3.2 есть баг, не позволяющий использовать tagof с именами тегов в качестве меток в switch (огромное спасибо ziggi, что сообщил об этом баге в комментариях).
К счастью, его можно обойти, заключив выражение с tagof в скобки:


stock Print({_, Float}:arg, arg_type=tagof(arg))
{
switch(arg_type)
{
case (tagof(_:)):
PrintInt(arg);
case (tagof(Float:)):
PrintFloat(arg);
case (tagof(bool:)):
PrintBool(arg);
}
}

Для удобства я выложу полное содержимое скрипта:



#include <a_samp>


stock PrintInt(i)
printf("int: %d", i);

stock PrintFloat(Float:f)
printf("float: %f", f);

stock PrintBool(bool:b)
printf("bool: %s", (b)?("true"):("false"));

stock Print({_, Float}:arg, arg_type=tagof(arg))
{
switch(arg_type)
{
case (tagof(_:)):
PrintInt(arg);
case (tagof(Float:)):
PrintFloat(arg);
case (tagof(bool:)):
PrintBool(arg);
}
}


main()
{
print("--Function overloading emulation test--");
Print(1);
Print(1.0);
Print(true);
}


Попробуем скомпилировать код: компилятор выплюнет варнинг "tag mismatch" на строке:

PrintBool(arg);
Похоже, следует перезаписать тег параметра функции тегом bool.

PrintBool(bool:arg);
(Интересно, почему такой же варнинг не выдаётся на аналогичном вызове PrintFloat()?)

Проверим код: на этот раз компилятор не выдаёт ни одной ошибки или предупреждения.
Теперь запустим скомпилированный скрипт на сервере SA:MP и проверим логи:


--Function overloading emulation test--
float: 1065353216.000000
bool: 1

Это и есть то, что нам нужно? Не совсем...
Во-первых, сразу бросается в глаза непонятное значение в строке "float: ".
Во-вторых, настораживает строка "int: ". Вернее, её полное отсутствие -_-
При этом вызов Print() с целочисленным параметром присутствует в функции main().

Разберёмся со всем по порядку.
Помните, что компилятор не выдал варнинга "tag mismatch" на вызове PrintFloat()?
Всё потому, что без перезаписи тега компилятор воспринимает параметр arg, как целочисленный, и делает так, чтобы он конвертировался в вещественное число с помощью функции float() во время выполнения скрипта.
Таким образом, вместо PrintFloat(arg) получается PrintFloat(float(arg)). Именно функция float и выдаёт то самое непонятное число в логах.
Проверим эту догадку: заменим тег arg на Float в вызове PrintFloat():


case tagof(Float:):
PrintFloat(Float:arg);

И снова скомпилируем файл: никаких варнингов или ошибок. Запускаем...


--Function overloading emulation test--
float: 1.000000
bool: 1

Минус одна проблема. Тем не менее, вывод целого числа всё ещё не работает, как надо.
Тут возможны 2 случая:
Компилятор как-то неправильно делает вызов функции PrintInt (или не делает его вообще).
Внутри функции Print значение arg_type не совпадает с tagof(_:).

Первое точно не вариант. Нет, ну серьёзно, кто будет релизить компилятор, который даже не может правильно сделать простой вызов функции!?
Остаётся только второе. Проверим, добавив отладочный вывод предположительно несовпадающих значений через printf.
При этом вызовы Print с вещественным и логическим значениями в функции main лучше закомментировать, чтобы отладочный вывод не повторялся 3 раза подряд.


stock Print({_, Float}:arg, arg_type=tagof(arg))
{
/**/printf("%d %d", arg_type, tagof(_:));
switch(arg_type)
{
case (tagof(_:)):
PrintInt(arg);
case (tagof(Float:)):
PrintFloat(arg);
case (tagof(bool:)):
PrintBool(arg);
}
}

main()
{
print("--Function overloading emulation test--");
Print(1);
//Print(1.0);
//Print(true);
}

Пустой комментарий "/**/" оставлен специально, чтобы был варнинг из-за неправильной табуляции.
Так будет проще вспомнить про то, что нужно убрать строку с отладочным выводом.
Компилируем скрипт и запускаем сервер:


--Function overloading emulation test--
0 --

Что мы видим: целочисленный тег имеет ID 0. Но что такое "--"?
На самом деле один из багов printf: функция не способна правильно вывести число -2147483648 (минимальное целочисленное значение в Pawn).
А значит наше предположение подтвердилось: ID тегов не совпадают (arg_type = 0, tagof(_:) = -2147483648).

Я не знаю, что это: баг компилятора или так задумано (https://lurkmore.to/Это_не_баг,_это_фича).
Но, как бы то ни было, нужно как-то обойти эту проблему.
Итак, оценим ситуацию:
arg не может иметь другого тега, кроме _, Float и bool.
Значение параметра arg_type для целочисленного arg не совпадает с tagof(_:).

Основываясь на этом, можно вынести вызов PrintInt в ветку default внутри того же switch.
Также не забываем убрать отладочный вывод.
И ни в коем случае не забудьте раскомментировать вызовы Print в функции main.

В итоге функция Print будет выглядеть так:


stock Print({_, Float}:arg, arg_type=tagof(arg))
{
switch(arg_type)
{
case (tagof(Float:)):
PrintFloat(Float:arg);
case (tagof(bool:)):
PrintBool(bool:arg);
default:
PrintInt(_:arg);
}
}





#include <a_samp>


stock PrintInt(i)
printf("int: %d", i);

stock PrintFloat(Float:f)
printf("float: %f", f);

stock PrintBool(bool:b)
printf("bool: %s", (b)?("true"):("false"));

stock Print({_, Float}:arg, arg_type=tagof(arg))
{
switch(arg_type)
{
case (tagof(Float:)):
PrintFloat(Float:arg);
case (tagof(bool:)):
PrintBool(bool:arg);
default:
PrintInt(_:arg);
}
}


main()
{
print("--Function overloading emulation test--");
Print(1);
Print(1.0);
Print(true);
}



Компилируем и запускаем:


--Function overloading emulation test--
int: 1
float: 1.000000
bool: true

Ну вот и всё, функция работает в точности так, как и было задумано.
Вот так в Pawn можно имитировать перегрузку функций. Вот только какой ценой...


P.S.: Эта статья была написана чисто из-за скуки во время пар.
Изначальной целью было не столько заставить пользователей использовать перегрузку функций в Pawn, сколько объяснить использование оператора tagof со всеми его достоинствами и недостатками.


Автор статьи: Daniel_Cortez (http://pro-pawn.ru/member.php?100-Daniel_Cortez)


Специально для Pro-Pawn.ru (http://www.pro-pawn.ru)
Копирование данной статьи на других ресурсах без разрешения автора запрещено!

$continue$
21.07.2015, 05:57
До изучение С++ не понимал, что это...
Теперь все понятно.

$continue$
21.07.2015, 16:33
А прототип шаблона функций из С++ возможен?
http://i.imgur.com/mwX4OZs.png

Daniel_Cortez
21.07.2015, 20:50
forward же...


forward SomeFunc();

main()
{
SomeFunc();
}

SomeFunc()
{
/* Do something. */
}


Стоит заметить, что в более ранних версиях Pawn ключевого слова forward не было и функции предварительно объявлялись без него.
В Pawn 3.2 тоже можно объявлять функции старым методом, эту возможность оставили для совместимости:


SomeFunc();

main()
{
SomeFunc();
}

SomeFunc()
{
/* Do something. */
}


Лично я предпочитаю второй способ, он выглядит более си-подобным.
Хоть он и считается устаревшим, куй вряд ли станет переводить SA:MP на Pawn 4.0 - из существующих сейчас скриптов ни один не сможет работать с новой версией языка, уж столько там изменений.
Да и Zeex со своей версией компилятора вряд ли станет нарушать совместимость с Pawn 3.2 (единственная фича, которую он убрал из компилятора - автоматическая защита от повторного включения инклуда, её он убрал, чтобы компилятор одинаково работал под разными ОС), так что нет никакой причины избегать того способа.

$continue$
21.07.2015, 21:44
forward же...


forward SomeFunc();

main()
{
SomeFunc();
}

SomeFunc()
{
/* Do something. */
}


Стоит заметить, что в более ранних версиях Pawn ключевого слова forward не было и функции предварительно объявлялись без него.
В Pawn 3.2 тоже можно объявлять функции старым методом, эту возможность оставили для совместимости:


SomeFunc();

main()
{
SomeFunc();
}

SomeFunc()
{
/* Do something. */
}


Лично я предпочитаю второй способ, он выглядит более си-подобным.
Хоть он и считается устаревшим, куй вряд ли станет переводить SA:MP на Pawn 4.0 - из существующих сейчас скриптов ни один не сможет работать с новой версией языка, уж столько там изменений.
Да и Zeex со своей версией компилятора вряд ли станет нарушать совместимость с Pawn 3.2 (единственная фича, которую он убрал из компилятора - автоматическая защита от повторного включения инклуда, её он убрал, чтобы компилятор одинаково работал под разными ОС), так что нет никакой причины избегать того способа.
Не forward, в Pawn придется указывать тип.

Daniel_Cortez
21.07.2015, 21:47
Не forward, в Pawn придется указывать тип.
О чём вы? В Pawn у функций, возвращающих целые числа, не нужно указывать тип.

$continue$
21.07.2015, 21:59
О чём вы? В Pawn у функций, возвращающих целые числа, не нужно указывать тип.

А если string или float?
Причём параметры могут быть разными (int, float, string, char, double)
Ах да, я не про возвращаемое значения, а тип в аргументах...

Daniel_Cortez
22.07.2015, 02:11
А если string или float?


Float:GetRandomFloat()
return Float:(random(cellmax) + random(cellmax));



GetRandomString(buffer[], size = sizeof(buffer))
for (buffer[--size] = EOS; size != 0; buffer[--size] = random(ucharmax-1)+1) {}



forward [MAX_PLAYER_NAME + 1] GetPlayerNameAlt(playerid);
GetPlayerNameAlt(playerid)
{
new name[MAX_PLAYER_NAME + 1];
GetPlayerName(playerid, name, sizeof(name));
return name;
}

Последний пример чисто для ознакомления. Возвращать массивы через стек с ограниченным размером - не самая лучшая идея.


Причём параметры могут быть разными (int, float, string, char, double)
Ах да, я не про возвращаемое значения, а тип в аргументах...
А разве не это рассматривалось в уроке (на примере одного параметра) ?

$continue$
22.07.2015, 02:47
Не, ну это перегрузка
https://ru.m.wikipedia.org/wiki/%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D1%8B_C%2B%2B

Daniel_Cortez
22.07.2015, 17:01
Не, ну это перегрузка
https://ru.m.wikipedia.org/wiki/%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D1%8B_C%2B%2B

Ах вот вы про какие прототипы...
Скажу честно, слабо знаком с ними, ибо в C++ сильно не углублялся. Но сомневаюсь, что есть что-то похожее в Pawn - там нет классов.
А для параметров переменного типа вполне хватит описанного в уроке трюка с tagof. Разве что, если параметров несколько, то они должны располагаться в порядке "параметр1, параметр2, ..., параметрN, tagof(параметр1), ..., tagof(параметрN)" - таким образом можно сделать скрытую передачу типов всех параметров. Единственный минус - нельзя передавать массивы (разве что с помощью #emit передавать указатели на массивы и делать собственную систему идентификации типов, чтобы отличать массивы от обычных переенных, но это уже явно перебор).

$continue$
19.08.2015, 06:17
Пример на С++, но это не С++, это - бородатый кодинг в стиле Си.


#include "stdafx.h"
#include <iostream>

using namespace std;

void Print(int);
void Print(double);
void Print(bool);

int main()
{
Print(1);
Print(1.0);
Print(true);
system("pause");
return 0;
}
// выводит на экран целочисленное значение
void Print(int arg)
{
cout << "int: " << arg << endl;
}

// выводит вещественное значение
void Print(double arg)
{
cout << "float " << arg << endl;
}

// выводит значение логического типа
void Print(bool arg)
{
// у функции printf нет спецификатора "%b" для bool, поэтому придётся
// реализовать вывод значений логического типа другим способом
cout.setf(ios::boolalpha);
cout << "bool: " << arg << endl;
}

"Чем лучше вы знаете C, тем труднее вам будет избежать программирования на C++ в стиле C, теряя при этом потенциальные преимущества C++" (C) Bjarne Stroustrup's.

Daniel_Cortez
19.08.2015, 12:59
#include "stdafx.h"
#include <iostream>

using namespace std;

void Print(int);
void Print(double);
void Print(bool);

int main()
{
Print(1);
Print(1.0);
Print(true);
system("pause");
return 0;
}
// выводит на экран целочисленное значение
void Print(int arg)
{
cout << "int: " << arg << endl;
}

// выводит вещественное значение
void Print(double arg)
{
cout << "float " << arg << endl;
}

// выводит значение логического типа
void Print(bool arg)
{
// у функции printf нет спецификатора "%b" для bool, поэтому придётся
// реализовать вывод значений логического типа другим способом
cout.setf(ios::boolalpha);
cout << "bool: " << arg << endl;
}



Пример на С++, но это не С++, это - бородатый кодинг в стиле Си.
Вы сделали пример из 1-го поста только ещё больше похожим на C++, использовав cout из iostream.
Да и предварительное объявление функций в крестах тоже часто используется.

Пельмень
22.08.2015, 01:54
Пример на С++, но это не С++, это - бородатый кодинг в стиле Си.


#include "stdafx.h"
#include <iostream>

using namespace std;

void Print(int);
void Print(double);
void Print(bool);

int main()
{
Print(1);
Print(1.0);
Print(true);
system("pause");
return 0;
}
// выводит на экран целочисленное значение
void Print(int arg)
{
cout << "int: " << arg << endl;
}

// выводит вещественное значение
void Print(double arg)
{
cout << "float " << arg << endl;
}

// выводит значение логического типа
void Print(bool arg)
{
// у функции printf нет спецификатора "%b" для bool, поэтому придётся
// реализовать вывод значений логического типа другим способом
cout.setf(ios::boolalpha);
cout << "bool: " << arg << endl;
}

"Чем лучше вы знаете C, тем труднее вам будет избежать программирования на C++ в стиле C, теряя при этом потенциальные преимущества C++" (C) Bjarne Stroustrup's.



template <typename T>
void Print (const T &t)
{
std::cout << typeid(t).name() << " " << t << std::endl;
}

Print<int>(10);
Print<bool>(true);
Print<float>(10.011);

Glant
25.07.2016, 18:27
Подскажите, что это такое ([MAX_PLAYER_NAME] рядом с заголовком функции)



GetPlayerNameAlt(playerid)[MAX_PLAYER_NAME]
{
new name[MAX_PLAYER_NAME];
GetPlayerName(playerid, name, sizeof(name));
return name;
}

TheMallard
25.07.2016, 18:35
o_0, а где ты такое увидел?

VVWVV
25.07.2016, 18:35
Подскажите, что это такое ([MAX_PLAYER_NAME] рядом с заголовком функции)



GetPlayerNameAlt(playerid)[MAX_PLAYER_NAME]
{
new name[MAX_PLAYER_NAME];
GetPlayerName(playerid, name, sizeof(name));
return name;
}


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

P.S.: Оно работает?

ziggi
25.07.2016, 18:45
Подскажите, что это такое ([MAX_PLAYER_NAME] рядом с заголовком функции)



GetPlayerNameAlt(playerid)[MAX_PLAYER_NAME]
{
new name[MAX_PLAYER_NAME];
GetPlayerName(playerid, name, sizeof(name));
return name;
}


Скорее всего просто опечатка, возникшая в результате копипаста.

По теме:
Разве так нельзя? Без переменных.

stock Print({_, Float, bool}:arg, arg_type=tagof(arg))
{
switch(arg_type)
{
case tagof(Float:):
PrintFloat(Float:arg);
case tagof(bool:):
PrintBool(bool:arg);
default:
PrintInt(arg);
}
}


UPD.

Проверил, так можно, только нужно поставить дополнительные скобки для tagof (иначе не скомпилируется):

stock Print({_, Float, bool}:arg, arg_type=tagof(arg))
{
switch(arg_type)
{
case (tagof(Float:)):
PrintFloat(Float:arg);
case (tagof(bool:)):
PrintBool(bool:arg);
default:
PrintInt(arg);
}
}

Daniel_Cortez
25.07.2016, 20:48
Это не валидный синтаксис, и скорее всего будут ошибки при компиляции, поэтому стоит удалить данный код (хотя, возможно, что это макрос).
Исправил.



P.S.: Оно работает?
Ну... по крайней мере задумывалось так, чтобы работало. Исправил тот пост.
Btw, вот где эта фича была замечена впервые: http://forum.sa-mp.com/showpost.php?p=2010371&postcount=32



Проверил, так можно, только нужно поставить дополнительные скобки для tagof (иначе не скомпилируется):

stock Print({_, Float, bool}:arg, arg_type=tagof(arg))
{
switch(arg_type)
{
case (tagof(Float:)):
PrintFloat(Float:arg);
case (tagof(bool:)):
PrintBool(bool:arg);
default:
PrintInt(arg);
}
}
Интересная находка... Не то, чтобы сильно полезная (в варианте с константами всё равно ничего лишнего в скомпилированный код не попадёт, пострадает только читаемость), но интересная.
Изначально я думал, что это такая фича языка, что нельзя пользоваться результатом tagof в switch. Хотя сейчас, спустя год после написания сей статьи, я не понимаю, как вообще можно было сделать такой вывод, это же явно баг.
Сейчас обновлю статью.


UPD: Ок, обновил статью ещё раз.
Только что проверил, в Pawn 4.0 этот баг остался.

@ziggi, не против, если напишу багрепорт в репо на GitHub, или ты сам?

ziggi
25.07.2016, 20:57
@ziggi, не против, если напишу багрепорт в репо на GitHub, или ты сам?

Напиши конечно, я даже не подумал об этом :blush:

Daniel_Cortez
26.07.2016, 13:36
Напиши конечно, я даже не подумал об этом :blush:
Три бага по цене одного. (https://github.com/compuphase/pawn/issues/20)

MassonNN
20.12.2019, 11:49
т.е., чтобы проверить, что переменная вещественного типа мне нужно делать вот так?:


_ISFLOAT ({_, Float}:__TO, __TYPE = tagof(__TO)) {

if (__TYPE == tagof(Float:)) return 666;

}

DeimoS
20.12.2019, 13:18
т.е., чтобы проверить, что переменная вещественного типа мне нужно делать вот так?:


_ISFLOAT ({_, Float}:__TO, __TYPE = tagof(__TO)) {

if (__TYPE == tagof(Float:)) return 666;

}

Эмм, а почему напрямую tagof не вызвать?

MassonNN
20.12.2019, 13:23
Эмм, а почему напрямую tagof не вызвать?

?

_ISFLOAT ({_, Float}:__TO) {

if (tagof(__TO) == tagof(Float:)) return 666;

}

DeimoS
20.12.2019, 13:44
?

_ISFLOAT ({_, Float}:__TO) {

if (tagof(__TO) == tagof(Float:)) return 666;

}

Нет. Избавится от функции _ISFLOAT (странное название, да ещё и капсом) вообще и работать напрямую с tagof в коде. Какой смысл создавать функцию ради одной строки?
Да и где вообще такая функция пригодиться может?

MassonNN
20.12.2019, 13:47
Нет. Избавится от функции _ISFLOAT (странное название, да ещё и капсом) вообще и работать напрямую с tagof в коде. Какой смысл создавать функцию ради одной строки?
Да и где вообще такая функция пригодиться может?

у меня просто код большой и я пытаюсь переводить все что можно на простые функции (привычка уже такая, меня вообще вымораживают си-подобные языки своей структурой, java в этом плане впереди на шагов так сто в сотой степени)


upd: а сама реализация то нормальная или нет?

DeimoS
20.12.2019, 14:03
stock IsVarTypeFloat({_, Float}:var, vartype = tagof(var))
{
#pragma unused var
return (vartype == tagof(Float:));
}

А лучше так
#define IsVarTypeFloat(%0) (tagof(%0) == tagof(Float:))

MassonNN
20.12.2019, 14:10
del

Seviel
19.04.2021, 13:44
Дико извиняюсь что поднимаю эту тему, на счёт целочисленного мне в голову пришел костыль:

stock Print({_, Float}:arg, arg_type=tagof(arg))
{
static const TAG_INTEGER;

switch(arg_type)
{
case (tagof(Float:)):
PrintFloat(Float:arg);
case (tagof(bool:)):
PrintBool(bool:arg);
case (tagof(TAG_INTEGER)):
PrintInt(_:arg);
}
#pragma unused TAG_INTEGER
}

execution
19.04.2021, 20:26
Дико извиняюсь что поднимаю эту тему, на счёт целочисленного мне в голову пришел костыль:

stock Print({_, Float}:arg, arg_type=tagof(arg))
{
static const TAG_INTEGER;

switch(arg_type)
{
case (tagof(Float:)):
PrintFloat(Float:arg);
case (tagof(bool:)):
PrintBool(bool:arg);
case (tagof(TAG_INTEGER)):
PrintInt(_:arg);
}
#pragma unused TAG_INTEGER
}


Дак достаточно использовать default если не нашли никакой тэг