Модераторы: bsa

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Макрос для определения количества аргументов. 
V
    Опции темы
Remiznik
Дата 13.3.2017, 11:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 379
Регистрация: 30.4.2005

Репутация: 1
Всего: 1



Хочу написать макрос который возвращал бы количество аргументов. Долго копался в интернете нашёл несколько вариантов но они не работали в VS 2015, как я понял из-за того что студия как-то по своему разворачивает __VA_VARGS__. Но удалось найти более менее работающий вариант
Код

#define RETURN_ARG_COUNT(_1_, _2_, _3_, _4_, _5_, count, ...) count

#define EXPAND_ARGS(args) RETURN_ARG_COUNT args

#define COUNT_ARGS_MAX5(...) EXPAND_ARGS((__VA_ARGS__, 5, 4, 3, 2, 1, 0))

int main()
{
    COUNT_ARGS_MAX5(); // ---- 1
    COUNT_ARGS_MAX5(int); // ----1 
    COUNT_ARGS_MAX5(int, float); //---- 2
    COUNT_ARGS_MAX5(int, float, double);// --- 3
}

проблема только в том, что для случая пустого вызова возвращает 1, может кто-то знает как это можно поправить ? 
PM MAIL   Вверх
azesmcar
Дата 13.3.2017, 12:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 52
Всего: 211



а зачем извращаться с макросами? вот на чистом C++
Код

constexpr unsigned int arg_count()
{
    return 0;
}

template <typename... T>
constexpr unsigned int arg_count(const T&...)
{
    return sizeof...(T);
}

int main()
{
    std::cout << arg_count() << std::endl;
    std::cout << arg_count(1) << std::endl;
    std::cout << arg_count(1, 2) << std::endl;
    std::cout << arg_count(1, 2, 3) << std::endl;
}

PM   Вверх
Remiznik
Дата 13.3.2017, 12:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 379
Регистрация: 30.4.2005

Репутация: 1
Всего: 1



Там задача чуть сложнее, этот макрос нужен чтоб получить идекс для функции. Тоесть идея такая, я макросом хочу создать функцию с N аргументами, а потом её использовать гдето в другом месте. 
Код

FNC(Name, int,  double); // создаёт функцию void fnc_Name(int _1, double _2) { //какойто код типа printf() }

fnc_Name(1, 3.0);


Максрос реализации 
Код


#define ARG_(T1) void
#define ARG_1(T1) T1 _1
#define ARG_2(T1, T2) T1 _1, T2 _2
#define ARG_3(T1, T2, T3) ARG_2(T1, T2), T3 _3

#define ARG(...) PRIMITIVE_CAT(ARG_, COUNT_ARGS(__VA_ARGS__))(__VA_ARGS__)

#define FNC(name, msg, ...)                \
    void fnc_##name(ARG(__VA_ARGS__)){ // do somthing } \


проблема в том что не получается получить нужный макрос ARG_
PM MAIL   Вверх
azesmcar
Дата 13.3.2017, 12:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 52
Всего: 211



Remiznik, все это можно сделать и через шаблоны. давай подробности если не получается. макросов лучше избегать по возможности.
PM   Вверх
Remiznik
Дата 13.3.2017, 12:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 379
Регистрация: 30.4.2005

Репутация: 1
Всего: 1



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

create_function(nameFnc, "text %d, %s", int, const char*);
// после этого гдето в коде можно использовать функцию по имени с реальными аргументами
nameFnc(2,"some"); // внутри просто sprinf() который сделает строку "text 2, some"


трудность в том что сначала надо определить список аргументов с типами, а потом их использовать. 
PM MAIL   Вверх
azesmcar
Дата 13.3.2017, 13:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 52
Всего: 211



а зачем для этого понадобилось создавать функции? я пока сути задачи не понимаю. в твоем конкретном случае

1. можно напрямую вызывать sprintf
2. лучше sprintf не вызывать вообще (если конечно пишешь не на C а на C++)

и зачем нужен ИНДЕКС функции? компилятор сам подставит нужную функцию в зависимости от количества параметров (перегрузка).
PM   Вверх
Remiznik
Дата 13.3.2017, 14:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 379
Регистрация: 30.4.2005

Репутация: 1
Всего: 1



Затем что в функцию зашивается константа с тексом, посмотри сигнатуру функции. Это для удобства. По каличеству параметров не подходит потому что у функций с разными именами могут быть одинаковое количество параметров. А так это всё только для удобства. 

Индекс нужен для ARG_№.

Это сообщение отредактировал(а) Remiznik - 13.3.2017, 14:20
PM MAIL   Вверх
azesmcar
Дата 13.3.2017, 14:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 52
Всего: 211



скажи для начала, на каком языке ты пишешь?

PM   Вверх
Remiznik
Дата 13.3.2017, 14:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 379
Регистрация: 30.4.2005

Репутация: 1
Всего: 1



с++
PM MAIL   Вверх
azesmcar
Дата 13.3.2017, 14:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 52
Всего: 211



Тогда избавляйся от sprintf, макросов и всего прочего. VS2015 поддерживает и variadic templates и много чего другого. Ты пытаешься на C++ писать неестественным для этого языка способом.
для форматирования строк есть boost::format(), для всего прочего - шаблоны.
это будет красиво, правильно, безопасно и переносимо.
я пока не совсем понимаю что конкретно ты хочешь сделать, потому не могу посоветовать конкретного решения, но во всяком случае то что ты пытаешься сделать нелегально smile

Это сообщение отредактировал(а) azesmcar - 13.3.2017, 14:54
PM   Вверх
Remiznik
Дата 13.3.2017, 14:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 379
Регистрация: 30.4.2005

Репутация: 1
Всего: 1



Я согласен. Но у меня есть конкретный вопрос по макросам, мне нужно посчитать количество аргументов и получить из этого другой макрос с нужным числом аргументов.  Для чего это нужно я уже объяснил для генерации специальной функции нужной мне сигнатуры. Шаблоны не дают возможности делать такую кодогенерацию.
PM MAIL   Вверх
Remiznik
Дата 14.3.2017, 10:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 379
Регистрация: 30.4.2005

Репутация: 1
Всего: 1



azesmcar, я написал код который работает, можешь посмотреть что получилось. Если знаешь как сделать по другому буду рад совету. 
Код

#define GET_ARG_COUNT(...)  INTERNAL_EXPAND_ARGS_PRIVATE(INTERNAL_ARGS_AUGMENTER(__VA_ARGS__))
#define INTERNAL_ARGS_AUGMENTER(...) unused, __VA_ARGS__
#define INTERNAL_EXPAND(x) x
#define INTERNAL_GET_ARG_COUNT_PRIVATE(_1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, count, ...) count
#define INTERNAL_EXPAND_ARGS_PRIVATE(...) INTERNAL_EXPAND(INTERNAL_GET_ARG_COUNT_PRIVATE(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0))

#define ARG_0() 
#define ARG_1(T1) T1 _1
#define ARG_2(T1, T2) T1 _1, T2 _2
#define ARG_3(T1, T2, T3) ARG_2(T1, T2), T3 _3
#define ARG(...) PRIMITIVE_CAT(ARG_, GET_ARG_COUNT(__VA_ARGS__))(__VA_ARGS__)

#define WRITE_MSG(msg, ...)                \
    {                                \
        char text[256];                    \
        sprintf(text, msg, __VA_ARGS__);    \
        std::cout<< text << std::endl;            \
    }                                \

#define WRITE_0(msg)    WRITE_MSG(msg)
#define WRITE_1(msg)    WRITE_MSG(msg, _1)
#define WRITE_2(msg)    WRITE_MSG(msg, _1, _2)
#define WRITE_3(msg)    WRITE_MSG(msg, _1, _2, _3)
#define WRITE(msg, ...) PRIMITIVE_CAT(WRITE_, GET_ARG_COUNT(__VA_ARGS__))(msg)

#define FNC(name, msg, ...)                    \
    void fnc_##name( ARG(__VA_ARGS__) ){    \
        WRITE(msg,__VA_ARGS__);            \
    }                                    \

FNC(funciton, "text  int %d", int);
FNC(funciton0, "text empty");
FNC(funciton1, "text %d %s", int, const char*);

int main()
{
        fnc_funciton(1);            // "text int 1"
    fnc_funciton0();                // "text  empty"
    fnc_funciton1(1, "char");        // "text  1 char"
}

идея в том что теперь эти функции можно использовать в любом месте программы, и когда тебе нужно будет что-то вызвать компилятор подскажет какие параметры для текста нужно подставить.
PM MAIL   Вверх
azesmcar
Дата 14.3.2017, 12:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 52
Всего: 211



Цитата(Remiznik @  14.3.2017,  10:00 Найти цитируемый пост)
azesmcar, я написал код который работает, можешь посмотреть что получилось. Если знаешь как сделать по другому буду рад совету. 

Ты написал абсолютно непонятный, нечитабельный и непереносимый код. во первых на gcc это скорее всего даже не скомпилируется
И вопрос даже не в том работает он или нет, вопрос в том, что такой код нельзя писать в приличном обществе реальных проектах.
Я не понимаю саму необходимость этого, но если оооочень надо, то пожалуйста.

легальные 11-ые плюсы.
Код

#include <iostream>
#include <functional>

template <typename...T>
void print_func(char const* fmt, T... args)
{
    char text[256];
    sprintf(text, fmt, args...);
    std::cout << text << std::endl;
}

using std::placeholders::_1;
using std::placeholders::_2;

auto hello_print_func = std::bind(print_func<int>, "Hello %d", _1);
auto bye_print_func = std::bind(print_func<int, int>, "Bye %d - %d", _1, _2);

int main()
{
    hello_print_func(1);
    bye_print_func(3, 2);
}


Это сообщение отредактировал(а) azesmcar - 14.3.2017, 12:36
PM   Вверх
Remiznik
Дата 15.3.2017, 11:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 379
Регистрация: 30.4.2005

Репутация: 1
Всего: 1



Супер, то что надо. Но вариант до редактуры мне понравился больше, только я не понял почему в нём нужно было передавать первым параметром шаблона char[] а с const char* не работало . 
PM MAIL   Вверх
azesmcar
Дата 15.3.2017, 12:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 52
Всего: 211



Цитата(Remiznik @  15.3.2017,  11:38 Найти цитируемый пост)
Супер, то что надо. Но вариант до редактуры мне понравился больше, только я не понял почему в нём нужно было передавать первым параметром шаблона char[] а с const char* не работало .  

шаблон требует external linkage.
http://www.comeaucomputing.com/techtalk/te.../#stringliteral

Это сообщение отредактировал(а) azesmcar - 15.3.2017, 14:23
PM   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.1595 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.