LINUX.ORG.RU

Передача параметров в функцию С++

 , ,


0

2

Проблема заключается в следующем. Есть функция, вот её прототип.

void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode);
есть так же класс
class Foo
{
    ..
    void ololo();
    ..
}
в его конструкторе я пытаюсь вызвать функцию attachInterrupt следующим образом
attachInterrupt(0, this->ololo, FALLING);
на что получаю ответ
error: cannot convert ‘Foo::ololo’ from type ‘void* (Foo::)()’ to type ‘void (*)()’
Понимаю, что вся проблема скорее всего в том, что надо правильно преобразовать типы, но не могу допереть как именно. Если вызывать attachInterrupt не из класса и не для члена класса, то всё работает. Подскажите пожалуйста, как правильно вызвать? Пните пожалуйста в нужном направлении, где я смогу раз и навсегда разобраться в этой теме.

★★★★

Последнее исправление: CYB3R (всего исправлений: 2)

Ололо это инстанс-метод, так что у него есть неявный параметр this, а также у него аби может быть thiscall виесто cdecl, так что под описанный прототип он не прет. Делай прокси-функцию, и как-то надо ей передать нужный this. Или делай ололо класс-методом, но я в крестах не силен, хз прокатит-нет.

arturpub ★★
()
Ответ на: комментарий от ilammy

делая так я не могу обращаться из метода ololo к другим членам этого же класса через this. как обойти?

WRG ★★★★
() автор топика
Ответ на: комментарий от WRG

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

Можно написать обертку, которая будет вызывать соотв. функцию подсовывая this из какой нить глобально переменной, но это жуткий костыль.

AIv ★★★★★
()

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

Если эта функция не использует поля конкретного объекта этого класса, то ее можно объявить static, как уже написали выше - но в этом случае в ней нельзя использовать this, который неявно передается в не-static методы класса.

Kiborg ★★★
()
Последнее исправление: Kiborg (всего исправлений: 1)

По хорошему тебе нужен bind. Есть и в std_c++11 и boost::bind

comp00 ★★★★
()
Ответ на: комментарий от Kiborg

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

4.2. Память выделена, и поля может использовать и методы вызывать и this у нее есть. RTFM.

AIv ★★★★★
()
Ответ на: комментарий от Kiborg

То есть другими словами: если функции ololo() необходимы поля конкретного экземпляра класса, как вы себе представляете вызов ololo() извне этого класса? Вот я процессор, поступило прерывание и мне нужно передать управление в ololo(). Что должно исполнять роль аргумента this?

Kiborg ★★★
()
Ответ на: комментарий от AIv

Уже поправился, понял что фигню написал. Оригинальную мысль см. ниже.

Kiborg ★★★
()
Ответ на: комментарий от Kiborg

Конструктор такой же метод как и все остальные. После первой { память под объект выделена, this приходит неявно через аргументы конструктора как и в других методах.

AIv ★★★★★
()
Ответ на: комментарий от WRG

Передавать this, очевидно же. Если надо передать коллбек с состоянием в сишный код, то забрасывают указатель на функцию типа void (*)(void*) где та void* — это юзерский контекст, который внутри коллбека кастуется к чему надо. Можно передать this так. Если там можно передавать плюсовые объекты, а указатель на функцию стоит просто из-за незнания чего бы-то ещё, то тут уже насоветовали всяких std::function.

ilammy ★★★
()
Ответ на: комментарий от AIv

Не совсем понял, причем тут конструктор... WRG , судя по коду, хочет повесить метод класса на прерывание. Вот идет исполнение кода в другом месте, где про класс Foo никто слыхом не слыхивал. И тут вдруг надо выполнить функцию Foo::ololo(), которая не static, и стало быть требует аргументом некий Foo *this. Откуда этот this возьмется и что будет в this->some_int_field? В том виде, как это написано, взять его неоткуда, о чем компилятор и сообщил.

А написал я это к тому, чтобы WRG задумался, что же ему нужно в этом коде сделать на самом деле.

Kiborg ★★★
()
Ответ на: комментарий от AIv

Я понимаю, что описали, но вот это

инстанс-метод

аби может быть thiscall виесто cdecl

передать коллбек

юзерский контекст

кастуется

вряд ли оставит хоть каплю желания разобраться в том, что же происходит, у человека, который не понимает почему в данном случае ‘Foo::ololo’ имеет тип ‘void* (Foo::)()’ и чем это отличается от ‘void (*)()’. (:

Kiborg ★★★
()
Ответ на: комментарий от Kiborg

Трамплины. В gcc (нестандартное расширение) так сделаны вложенные функции в C, которые работают как замыкания.

Пишут, что в C++14/17 возможно добавят каст из экземпляров типов с operator() в указатель на функцию, как раз для подобных случаев, реализовать это скорее всего можно только (ну, или по крайне мере проще всего) через трамплины.

Да, исполняемый стек, небезопасно и вообще костыли и ужас (не сарказм).

xeiph
()
Ответ на: комментарий от Kiborg

Пипец вы тут за ночь демагогию развели... Прокси функция, глобальный Foo*, все. Прототип аттача не подразумевает другого использования и/или идентификации события. Че за феерическое небыдло в треде?

arturpub ★★
()
Ответ на: комментарий от arturpub
static Foo *lalka __attribute__((unskilled)) = NULL;

static void
trololo(void)
{
    lalka->ololo();
}

int
main(int argc, char *argv[])
{
    lalka = new Foo(); // или Foo foo; lalka = &foo;
    attachInterrupt(0, trololo, FALLING);
    return 0;
}
arturpub ★★
()
Ответ на: комментарий от arturpub

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

WRG ★★★★
() автор топика
Ответ на: комментарий от arturpub

это что такое?

__attribute__((unskilled))

WRG ★★★★
() автор топика
Ответ на: комментарий от WRG

Если в attachInterrupt тоже твой код, его лучше изменить на (int, void (*cb)(void *ud), void *ud, int), чтобы можно было ud в cb передавать, оно и будет твой this.

static void
trololo(void *plalka)
{
    Foo *lalka = <whatever_cast>plalka;
    lalka->ololo();
}

int
main(int argc, char *argv[])
{
    lalka = new Foo(); // или Foo foo; lalka = &foo;
    attachInterrupt(0, troll, lalka, FALLING);
    return 0;
}

__attribute__((unskilled))

Нужен только при -std=shk97, можно просто выкинуть.

arturpub ★★
()

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

anonymous
()
Ответ на: комментарий от WRG

Объяви attachInterrupt как:

void attachInterrupt(uint8_t interruptNum, std::function<void>, int mode);
KblCb ★★★★★
()
Ответ на: комментарий от nanoolinux

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

KblCb ★★★★★
()
Ответ на: комментарий от Gorthauer

Лямбда с захватом this не пройдёт по сигнатуре, если я не ошибаюсь.

KblCb ★★★★★
()
Ответ на: комментарий от nanoolinux

Ему вроде нельзя исходную функцию переделывать. Так что или глобальный указатель или thread-local указатель или же какие-то компиляторозависимые плюшки уже.

anonymous
()
Ответ на: комментарий от WRG

знаю, что делю на ноль весь тред, но вот так вот.

WRG ★★★★
() автор топика
Ответ на: комментарий от nanoolinux

Не занимайся хернёй. Это задача не для спп, а для С.

о потоках речи не идёт, выполняется всё на микроконтроллере AVR

Так мопед не мой. Но это к слову нисколько не упрощает ответ на вопрос как хранить список колбеков если не в std::function и не по указателю.

KblCb ★★★★★
()
Ответ на: комментарий от WRG

и да, attachInterrupt не мой, стандартная адруиновская библиотека.

Кто же пользуется на микроконтроллерах стандартными библиотеками? Помилуйте, этого совершенно нельзя делать. А если серьёзно, то вероятнее всего дёргать свой колбек ты будешь из одного конкретного объекта. Сделай этот объект синглетоном. Вокруг вызова указателя на синглетон и вызова метода оберни функцию, указатель на функцию-обёртку передавай в attachInterrupt. Всё.

KblCb ★★★★★
()
Ответ на: комментарий от KblCb

как хранить список колбеков

дай угадаю... мм.. в списке?

У тс проблема в том, что он не знает чем отличается указатель на методы класса от указателя на ф-ю. Собственно и ответ на вопрос тс такой: никак (без костылей). Либо делать массив указателей на ф-ии, либо связаные структуры. Но я даже бояюсь представить нафига нужен связный список указателей на обработчики прерываний. Да и вообще, микроконтроллеры и с++ это какой-то упоротый постмодернистский сюрреализм кмк.

nanoolinux ★★★★
()
Ответ на: комментарий от AIv

и ты что-то говорил про быдлокодерство

но это костыль

и с каких пор bind, который с некоторого времени уже даже в стандарте, стал костылем?

Stil ★★★★★
()
Ответ на: и ты что-то говорил про быдлокодерство от Stil

Я так понял что тут собрался народ, специально покостылять, ибо все посты о bind они игнорят.
При этом ТС еще удивляется:

Хотел сделать красиво, как у людей, получилось как всегда.

comp00 ★★★★
()
Ответ на: комментарий от comp00

bind не даст тебе нужной сигнатуры. На выходе bind'а std::function, а ТС нельзя менять сигнатуру функции.

KblCb ★★★★★
()
Ответ на: комментарий от anonymous

мой фейл. с c-api не выходит каменный цветок.

Stil ★★★★★
()

в общем, пока что сделал так

class Foo
{
    ..
    void ololo();
    ..
}

void leftOptoInterrupt()
{
    foo.ololo();
}

int main()
{
    Foo foo;
    attachInterrupt(0, leftOptoInterrupt, FALLING);
}
WRG ★★★★
() автор топика
Ответ на: комментарий от WRG

Я надеюсь, что ты понимаешь, что foo в main и в leftOptoInterrupt — разные вещи.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.