Указатель на функцию с переменным числом аргументов

anarch
Offline
Зарегистрирован: 10.09.2017

Ситуация такая, передаю в функцию указатель на функцию.

void function(){
  EEPROM.put(0,var);
}

void millisTimer(uint32_t &previousTime, uint32_t interval,
                 void (*function)())
{
  if (millis() - previousTime > interval)
  {
    previousTime = millis(); 
    function();
  }
}

millisTimer(previousTime, 1000, function);

Так работает замечательно, но если я передаю напрямую EEPROM.put(0,var); валятся ошибки.

Пробовал через шаблон то же не получаеться.

template <typename T, typename... ArgTypes>
void millisTimer(uint32_t &previousTime, uint32_t interval,
                 Т (*function)(ArgTypes... arg))
{
  if (millis() - previousTime > interval)
  {
    previousTime = millis(); 
    function();
  }
}

millisTimer(previousTime, 1000, EEPROM.put(0,var));

Так же с ошибками. Помогите разобраться.

astwo
Offline
Зарегистрирован: 10.07.2019

Здесь надо лямдофункцию организовывать

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

anarch пишет:
но если я передаю напрямую EEPROM.put(0,var);.

И как же Вы это делаете? Секрет?

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Памойму, это не адрес функции, а её вызов в этом месте. 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, скетча мы не видели, а потому, хрен его знает что там.

anarch
Offline
Зарегистрирован: 10.09.2017

Var любого типа в том числе и структура.

Про лямдафункцию вчера начал читать, но поздно уже было. Сегодня продолжу изучение.

Уже начинаю понимать природу ощибок.

Действително я вызываю функцию, а не передаю.

Нужно делать как то так:

millisTimer(previousTime,  interval, EEPROM.put, 0, var);

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

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

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

самое страшноя, что EEPROM.put - сама есть шаблонная функция. 

anarch
Offline
Зарегистрирован: 10.09.2017

А что в этом страшного если не секрет?

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

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

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

anarch пишет:

Нужно делать как то так:

millisTimer(previousTime,  interval, EEPROM.put, 0, var);

Нет, так делать не нужно. С шаблонами так не работают.

anarch
Offline
Зарегистрирован: 10.09.2017

Если бы мой кругозор был настолко велик не было бы данной темы. Поэтому и обратился за помошью.

ЕвгенийП пишет:

anarch пишет:

Нужно делать как то так:

millisTimer(previousTime,  interval, EEPROM.put, 0, var);

Нет, так делать не нужно. С шаблонами так не работают.

а как нужно делать?

Пришол вот к такому виду.

template <typename T, typename... Args>
T millisTimer(uint32_t &previousTime, const uint32_t interval,
              T (*function)(), Args&... args);

Но если пытаюсь передать параметры все равно ошибки.

И да же если не шаблонную функцию передовать все равно не получаеться.

Немного нашел информации:

https://docs.microsoft.com/ru-ru/cpp/cpp/lambda-expressions-in-cpp?view=vs-2019

https://docs.microsoft.com/ru-ru/cpp/cpp/ellipses-and-variadic-templates?view=vs-2019

Вот кусок кода как пример что я хочу получить.

#include <iostream>

using namespace std;

void print() {
    cout << endl;
}

template <typename T> void print(const T& t) {
    cout << t << endl;
}

template <typename First, typename... Rest> void print(const First& first, const Rest&... rest) {
    cout << first << ", ";
    print(rest...); // recursive call using pack expansion syntax
}

int main()
{
    print(); // calls first overload, outputting only a newline
    print(1); // calls second overload

    // these call the third overload, the variadic template,
    // which uses recursion as needed.
    print(10, 20);
    print(100, 200, 300);
    print("first", 2, "third", 3.14159);
}

 

anarch
Offline
Зарегистрирован: 10.09.2017

Забудем навсегда про EEPROM.put

Цель стоит не переписывать каздый раз конструкцию с millis().

if (millis() - previousTime > interval)
  {
    previousTime = millis();  
    myFunction(args);
  }

А вынести ее в отдельную функцию передать предыдущее значение millis(), интервал и функцию которая дожна выполниться.

Все хорошо работает с void или когда известно число и тип аргументов функции.

template <typename T>
T millisTimer(uint32_t &previousTime, const uint32_t interval,
              T (*function)(int), int a); 

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

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

anarch пишет:

а как нужно делать?

Для начала Вы попытайтесь внятно объяснить ЧТО нужно делать, а потом уже поговрим "как". Сначала Вы скзали, что надо передавать указатели на функции с переменным числом параметров, потом, что это должны быть шаблоны, потом уж лямбды - что будет в следующем посте?

Вы можете внятно и спокойно объяснить что нужно сделать. Не предлагать свои решения, а просто сказать "что"?

anarch пишет:

Пришол вот к такому виду.

Давайте, я не будe комментировать :)

anarch пишет:

Если бы мой кругозор был настолко велик не было бы данной темы. Поэтому и обратился за помошью.

Немного нашел информации:

Забудьте про лямбды. Ибо "если бы Ваш кругозор был настолко велик", Вы бы могли их использовать, а так - забудьте. Вы даже не знаете для чего они нужны, ну и чего суётесь в воду, не зная броду?

anarch пишет:

Вот кусок кода как пример что я хочу получить.

Ну, и где в этом коде передача указателя на функцию? Ещё раз, к началу моего поста, объясните наконец внятно, что же Вам нужно-то? Только внятно, словами, а не примерами и, Боже упаси, без Ваших идей готовых решений на лямбдах, шаблонах, или ещё на чём.

anarch
Offline
Зарегистрирован: 10.09.2017

Пост выше я написал, что хочу получить.

И если не затруднит коментируйте ;) 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

anarch пишет:

template <typename T>
T millisTimer(uint32_t &previousTime, const uint32_t interval,
              T (*function)(int), int a); 

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

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

Вы пытаетесь использовать шаблоны как мартышка очки. Угадал? Не выйдет, читайте нормальную литературу про шаблоны. Без понимания там трудно.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ладно, сейчас я убегаю, вернусь в сеть вечером, попрбуйте пока понять что такое Т в Вашей записи и внимательно читайте в моём предыдущем посте что именно Вы на самом деле сделали.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Ну а я, как неугадавшый, самоудалюся

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

anarch, ну как вам наш местный Моисей(ЕвгенийП) . С такими проводниками вы или 40 лет будете ходить до земли обетованой. Или выведет вас вместо Одессы на Херсон. 
  Вы изначально взяли не тот инструмент для решения задачи, только и всего. Решать надо через лямдафункции. Но новичкам их не предлагают. Дедовщина она и на форуме дедавщина.:(

/**/
#include <EEPROM.h>
typedef  void (*pDo)();
void millisTimer(uint32_t &previousTime, uint32_t interval, pDo Do) {
  if (millis() - previousTime > interval) {
    previousTime = millis();
    Do();
  }
}
unsigned long previousTime = 0;
unsigned long previousTime1 = 0;
int var = 12;
void setup() {
  Serial.begin(9600);
}
void loop() {
  millisTimer(previousTime, 1000, [] {EEPROM.put(0, var);});
  millisTimer(previousTime1, 1000, [] {Serial.println("Tuc");});
}

 ПС: Просто иногда контрабандой из под полы предлагаю.Последнюю отдал.

Logik
Offline
Зарегистрирован: 05.08.2014

Сдается мне что это не совсем то, что хочет в #11.

Надо в таймере на миллисе вызывать ф-ции с произвольным кол-вом аргументов, а тут в стр.7 вобще без аргумента. Понятно что сунув туда обертку на функцию с аргументами можна выкрутится через глобальные, как в стр.17 var сделана. Но наверно это не очень. У лямд там в [] можна койчего писать еще ;) может так пройдет. 

Я бы шото такое пробовал. Собирается но передачу данных в Fn сами проверяйте.

int Fn(...){Serial.print("Fn"); return 6;}


uint32_t previousTime;

template <typename T, T (*func)(...)>
T millisTimer(uint32_t &previousTime, uint32_t interval, ... )
{
  if (millis() - previousTime > interval)
  {
    previousTime = millis(); 
    
    va_list arg_ptr;
    va_start(arg_ptr, interval);
    func(arg_ptr);
    va_end(arg_ptr);
  }
}


void setup() {
  // put your setup code here, to run once:

}

void loop() {
  // put your main code here, to run repeatedly:
 uint32_t previousTime = millis();
millisTimer<int, Fn>(previousTime, 1000, 1,2);
millisTimer<int, Fn>(previousTime, 1000, 1,2,3,4);

}

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

anarch
Offline
Зарегистрирован: 10.09.2017

qwone, Logik, огромное спасибо! 

Но код от qwone более безопасен. Теперь понял, что не в том направлении двигался ;)

Если я все правилно понимаю в лябда функции можно выполнять кусок кода?

Для примера проверять линк:

 millisTimer(previousTime, 1000, [] {
    if (Ethernet.linkStatus() == LinkOFF) {
      Serial.println("Ethernet cable is not connected.");
    }
  });

А что если я захочу, что бы millisTimer возращала что нибудь.

[] {return myFunc();}

Натолкните в какой сторону изучать.