Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 8, средняя оценка - 4.75
daslex
1271 / 515 / 106
Регистрация: 02.08.2011
Сообщений: 2,706
#1

Функция должна принять указатель на саму себя - C++

07.01.2014, 22:48. Просмотров 1197. Ответов 46
Метки нет (Все метки)

не рекурсия. (ошибка в названии)
Функция должна принять указатель на саму себя.
моя неверная попытка имеет вид
C++
1
2
3
4
5
6
7
8
9
10
11
int myfunc(int (*P)(int))  принимаю указатель на функцию
{
   return 0;
}
 
int main()
{
  int (*P)( int (*)(int) ); //создаю указатель на функцию
  P=myfunc; //присваиваю в указатель адрес функции
  myfunc(P); //попытка передарь функции указатель на саму себя. неверная.
}
Это как делается?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
07.01.2014, 22:48
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Функция должна принять указатель на саму себя (C++):

Функция должна возвращать указатель на первый элемент массива,удовлетворяющий условию - C++
Функция должна возвращать указатель на первый элемент массива,удовлетворяющий условию(в данном случае используется указатель на бинарный...

Подскажите немножко с рекурсией ( Функция должна вызывать сама себя до тех пор пока sum не станет больше х) - C++
Вводим число х. Функция должна вызывать сама себя до тех пор пока sum не станет больше х. Но программа выдает ошибку, Подскажите в чем...

Перемножить матрицу на саму себя - C++
Подскажите пожалуйста, как можно реализовать эту задачу: Нужно будет перемножить матрицу на саму себя. Вот пример: Матрица 1: 0 A B ...

Почему C++ программа не удаляет саму себя? - C++
Имеется следующий код (файл 01del.cpp): #include <windows.h> using namespace std; int main() { system("del /q...

Как принять код клавиши, а вписать саму клавишу? (Принимает "57", что означает "9") - C++
Нужно избавиться от такой глупости: char ch = 0; if(ch=='1')mas=1; if(ch=='2')mas=2; if(ch=='3')mas=3; ...

Функция, принимающая указатель и число байт и выделяющая память под указатель - C++
Здравствуйте. Задача легкая, но почему-то завис Нужно написать функцию, принимающую указатель и число байт и выделяющую память под...

46
hoggy
6636 / 2821 / 484
Регистрация: 15.11.2014
Сообщений: 6,240
Завершенные тесты: 1
21.09.2015, 18:56 #31
Цитата Сообщение от daslex Посмотреть сообщение
Вовнутрь функции передается функция., а должен был указатель на неё. Т.е. созданный указатель, который указывает на foo должен был передаться вовнутрь foo., а не foo вовнутрь foo.
ну на самом деле передача foo(foo);
это тоже самое, что и foo(&foo);

следущий пример иллюстрирует это положение:

http://rextester.com/BICQ84301

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
#include <iostream>
#include <functional>
 
class recursivePointer
{
    typedef std::function<void(const size_t)> 
        functor;
public:
    template<class T> recursivePointer(T&& v)
        :mCaller( std::bind(v, v, std::placeholders::_1) )
    {}
    
    recursivePointer(const functor& v)
        :mCaller(v)
    {}
    recursivePointer(functor&& v)
        :mCaller( std::move(v) )
    {}
    
    void operator()(const size_t depth)const 
        { mCaller(depth); }
    
    operator const functor&()const
        { return mCaller; }
    
private:    
    functor mCaller;
};
 
void foo(const recursivePointer& f, const size_t depth)
{
    if(depth == 0)
        return;
    
    std::cout<<"depth recursieve: "<< depth << '\n';
    f(depth - 1);
}
 
int main()
{
    std::cout << "Hello, world!\n";
    
    const auto pFunc = recursivePointer(&foo);
    
    foo(pFunc, 10);
    std::cout<< "--------------\n";
    
    foo(foo, 10);
    std::cout<< "--------------\n";
    
    foo(&foo, 10);
    std::cout<< "--------------\n";
}
1
daslex
1271 / 515 / 106
Регистрация: 02.08.2011
Сообщений: 2,706
21.09.2015, 19:09  [ТС] #32
Вот же блин. Это не совсем то же самое. У указателя, если его создать, будет свой собственный адрес памяти, отличный от адреса foo. И его при необходимости можно перенаправить, в отличии от &foo, так как непосредственно у foo адрес поменять невозможно.

Может я не очень грамотно выражаюсь, но псевдокод
C++
1
2
3
4
5
6
7
8
foo1(*ptr){}; //Внутри указатель
foo2(*ptr){}; //Внутри указатель
...
*ptr = foo1(ptr);  //Сделали указатель на foo1 и отдали его вовнутрь ;
**ptr; //Подобие разыменования вызывает функцию foo1, а вовнутрь отдается ptr.
 
*ptr = foo2(ptr); //Сделали указатель на foo2 и отдали его вовнутрь;
**ptr; //Подобие разыменования вызывает foo2, а вовнутрь отдается ptr.
Лично мне чем-то отдаленно полиморфизм напоминает.
Притягивать за уши не надо. Решения нет.

Добавлено через 2 минуты
Вы это лучше меня знаете. Я не понимаю, чем я вынуждаю Вас с этим вот спорить.
0
hoggy
6636 / 2821 / 484
Регистрация: 15.11.2014
Сообщений: 6,240
Завершенные тесты: 1
21.09.2015, 19:22 #33
Цитата Сообщение от daslex Посмотреть сообщение
Я не понимаю, чем я вынуждаю Вас с этим вот спорить.
я с вами и не спорил.
вместо этого я прям у вас на глазах написал код,
который реализует "рекурсивный указатель на функцию".

мой пример-иллюстрация (см #31)
иллюстрирует весь ваш псевдокод.

собственно, вот это главное,
чего вы хотите получить:
C++
1
const auto pFunc = recursivePointer(&foo);
0
daslex
1271 / 515 / 106
Регистрация: 02.08.2011
Сообщений: 2,706
21.09.2015, 19:51  [ТС] #34
Я не понимаю этого кода, но вижу, что он вообще не похож на показанный псевдокод.
Я сейчас не доказываю, что это не то или что это то. Я не вижу того, что я ожидал. Вопрос не в рекурсивном указателе на функцию. А в функции, вовнутрь которой приходит указатель, который уже показывает на адрес функции, в которую он пришел.

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

Вот как-то так вот витиевато все.
Это не мое самолюбие. Я правда не вижу этого у Вас в коде.

Добавлено через 7 минут
C++
1
2
3
foo(pFunc,
foo(foo,
foo(&foo
должно иметь вид (псевдокод).
C++
1
2
3
**ptr; //Обычным разыменованием указателя Вызвал функцию. Если внутри нее разыменовать ptr, то рекурсия
ptr = foo2; //Указатель указывает на другую функцию
**ptr; //Вызвал функцию. Если внутри нее разыменовать ptr, то рекурсия, но уже вот текущей функции
0
hoggy
6636 / 2821 / 484
Регистрация: 15.11.2014
Сообщений: 6,240
Завершенные тесты: 1
21.09.2015, 20:02 #35
Цитата Сообщение от daslex Посмотреть сообщение
А в функции, вовнутрь которой приходит указатель, который уже показывает на адрес функции, в которую он пришел.
так и есть.

вы ж понимаете, что делает операция взятия адреса?
результатом такой операции является указатель,
который хранит адрес объекта.

смотрите:
C++
1
2
3
// во внутрь foo попадает объект, 
// который является указателем на функцию foo
foo(&foo, 10);
если нужно придержать снаружи,
тогда вот, пожалуйста:

C++
1
2
3
4
5
// --- срисовали
const auto pFunc = recursivePointer(&foo);
 
// чуть позде можно будет запускать:
foo(pFunc, 10);



Цитата Сообщение от daslex Посмотреть сообщение
Вовнутрь функции должен передаваться указатель. При этом в разные моменты времени, в зависимости от того, на какую функцию указывает указатель, разыменование указателя приводит к вызову функции, в которую как параметр приходит адрес на начало самой себя. Т.е. если внутри функции просто разыменовывать пришедший в нее указатель, то должна происходить рекурсия.
так и есть, за исключением того, что разыменовывать не нужно:

C++
1
2
3
4
5
6
7
8
9
10
11
// --- принимает рекурсивный указатель на саму себя
void foo(const recursivePointer& f, const size_t depth)
{
    if(depth == 0)
        return;
    
    std::cout<<"depth recursieve: "<< depth << '\n';
 
    // --- дергает саму себя по указателю
    f(depth - 1);
}
строго говоря,
даже самый обычный указатель на функцию не нужно разыменовывать,
что выполнить запуск функции по указателю.

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

Цитата Сообщение от daslex Посмотреть сообщение
Я правда не вижу этого у Вас в коде.
ну даже если вы не владеете магией шаблонов,
тем менее вы не можете не увидеть,
что в функцию foo передается адрес функции foo.
и что сама функция foo запускает сама себя дергая себя через рекурсивный указатель.

кроме того, просто рассуждайте логически:
как компилятор мог догадаться, что нужно вызывать именно foo?
он же не с потолка это взял.

он знает, что нужно рекурсивно запускать функцию foo,
потому что я скормил ей указатель на саму себя.

можно было бы скормить что нибудь другое.
но тогда и вызвалось бы тоже что-то другое.
и не было бы рекурсии.

Добавлено через 3 минуты
Цитата Сообщение от daslex Посмотреть сообщение
**ptr; //Обычным разыменованием указателя Вызвал функцию.
нет, так не годится.

технически это конечно можно.
но так не делают.

вот вам простейший встречный вопрос: предположим, нужно вызвать функцию с параметрами.
пускай там будет два инта.
и как вы эти параметры передадите?

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

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

C++
1
2
3
4
5
6
7
8
9
10
void foo(const recursivePointer& f, const size_t depth)
{
    if(depth == 0)
        return;
    
    std::cout<<"depth recursieve: "<< depth << '\n';
 
    // --- вызвать саму себя, передав явный дополнительный аргумент
    f(depth - 1);
}
но ещё повторюсь:
это уже вопросы дизайна.
этакая косметика.
сделать то можно по всякому.
1
daslex
1271 / 515 / 106
Регистрация: 02.08.2011
Сообщений: 2,706
21.09.2015, 20:18  [ТС] #36
глупый вопрос.
если pFunc это указатель
Цитата Сообщение от hoggy Посмотреть сообщение
const auto pFunc = recursivePointer(&foo);
то почему я не могу применить к нему cout ?

Добавлено через 2 минуты

Не по теме:

я не буду делать акцент на разыменовании для вызова. Это больше было написано как для "импульса к действию", а не действительная потребность.

0
hoggy
6636 / 2821 / 484
Регистрация: 15.11.2014
Сообщений: 6,240
Завершенные тесты: 1
21.09.2015, 20:32 #37
Цитата Сообщение от daslex Посмотреть сообщение
если pFunc это указатель
Цитата Сообщение от daslex Посмотреть сообщение
то почему я не могу применить к нему cout ?
потому что я не заложил в него такую возможность.

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

однако с позиции своих знаний, я заявляю:
что все операции, присущие сырым указателям на функцию,
либо указателям на функцию-член - реализуются.
причем закодить это не сложно.

но нужно чутка понимать шаблоны и type erasure.
0
daslex
1271 / 515 / 106
Регистрация: 02.08.2011
Сообщений: 2,706
21.09.2015, 20:40  [ТС] #38
А с каких пор в указатели можно закладывать возможности?
Указатели, о которых говор я - встроенный тип данных, такой же тип как, например int.
Насколько мне известно, в такие типы свои возможности заложить невозможно.
0
hoggy
6636 / 2821 / 484
Регистрация: 15.11.2014
Сообщений: 6,240
Завершенные тесты: 1
21.09.2015, 20:55 #39
Цитата Сообщение от daslex Посмотреть сообщение
А с каких пор в указатели можно закладывать возможности?
Указатели, о которых говор я - встроенный тип данных, такой же тип как, например int.
Насколько мне известно, в такие типы свои возможности заложить невозможно.
у вас была задача - поиметь возможность пнуть самого себя рекурсивно через указатель на функцию.
я предоставил вам решение, которое позволяет это сделать.

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

но возможным это становится благодаря некой обертке:
C++
1
const auto pFunc = recursivePointer(&foo);
которая выполняет некие магические танцы с бубнами,
что бы обмануть "вечную рекурсию".

и это - красноречивый пример идеалогии языка с++ в действии:
способность расширять свои возможности за счет кода,
написанного на нем самом.
1
daslex
1271 / 515 / 106
Регистрация: 02.08.2011
Сообщений: 2,706
21.09.2015, 21:15  [ТС] #40
Всё, что в class мне неизвестно, следовательно непонятно в принципе.
typedef - фиг с ним, синоним.

в mCaller что-то записывается, только что непонятно. Также непонятно что символизирует название mCaller. Что-то типа "Кнопка спуска"?
Цитата Сообщение от hoggy Посмотреть сообщение
mCaller( std::bind(v, v, std:laceholders::_1)
Непонятно. Похоже на функцию без типа, только не понятно что это на самом деле и почему типа не видно.
Цитата Сообщение от hoggy Посмотреть сообщение
recursivePointer(const functor& v)
* * * * :mCaller(v)
* * {}
Остальное тоже внутри класса непонятно, но для начала понять вышеуказанное мне не помешало бы.
0
hoggy
6636 / 2821 / 484
Регистрация: 15.11.2014
Сообщений: 6,240
Завершенные тесты: 1
21.09.2015, 21:28 #41
Цитата Сообщение от daslex Посмотреть сообщение
Всё, что в class мне неизвестно, следовательно непонятно в принципе.
на самом деле там ничего сложного и сверъестественного нет.

я мог бы вам объяснить, как работает такая магия.
но только если вы понимаете шаблоны хотя бы на базовом уровне.
0
daslex
1271 / 515 / 106
Регистрация: 02.08.2011
Сообщений: 2,706
21.09.2015, 21:37  [ТС] #42
На базовом понимаю. Зачем они нужны тоже понимаю. Однозначно знаю не всю подноготную, но малая, вводная часть о шаблонах мне известна. Что Вы понимаете под базовым уровнем не очень понимаю. Понятие базовых знаний у людей обычно отличается. Как они там делают "большое пузо" небольшим с виду кодам, например, плохо понимаю, только в общих чертах.
0
hoggy
6636 / 2821 / 484
Регистрация: 15.11.2014
Сообщений: 6,240
Завершенные тесты: 1
21.09.2015, 22:11 #43
Цитата Сообщение от daslex Посмотреть сообщение
На базовом понимаю. Зачем они нужны тоже понимаю. Однозначно знаю не всю подноготную, но малая, вводная часть о шаблонах мне известна. Что Вы понимаете под базовым уровнем не очень понимаю. Понятие базовых знаний у людей обычно отличается. Как они там делают "большое пузо" небольшим с виду кодам, например, плохо понимаю, только в общих чертах.
тогда поехали:

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

предположим, есть неккий класс "кнопка".
и если на кнопку нажали - пусть она предупредит наш клиентский код об этом событии.

но проблема в том, что "кнопка" - это библиотечный класс, который ничего о нас не знает
как же она сможет прудепредить нас о нажатии, если она ничего о нас не знает?

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


вот так это может выглядеть в коде:

http://rextester.com/TSIWEX43141

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
#include <iostream>
#include <functional>
 
struct button
{
 
    typedef std::function<void()>
        callback;
    
    
    callback onPressed;
    
    
    void simulatePressed()
    {
        if(onPressed)
            onPressed();
    }
};
 
 
void if_pressed()
{
    std::cout<<"на кнопку нажали\n"; 
}
 
int main()
{
    std::cout << "Hello, world!\n";
    
    button b;
    b.onPressed = if_pressed;
    
    
    b.simulatePressed();
}
кнопка ничего о нас не знает.
но мы указали ей, что нужно дернуть,
что бы нас предупредить.


теперь следущий шаг:
вы наверное уже заметили,
что всю грязную работу на себя берет чудесный механизм std::function.

как он это делает?

концептуальная схема:
http://rextester.com/QXLF72730


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
#include <iostream>
 
 
// --- будем запускать её
int foo() { std::cout<< __PRETTY_FUNCTION__ << std::endl; return 0; }
 
 
// --- общий шаблон - не функционирует
// попытка вызвать его для абы какого T будет приводить
// к ошибкам компиляции
template<class T>struct delegate;
 
    
// --- специализация для случая, когда делегат
// это функция    
template<class R, class... Args>
struct delegate<R(Args...)>
{
    // из шаблона выводится тип функции
    // которую нужно запустить.
    typedef R(*pFunc)(Args...);
    
    
    // --- нацеливание делегата в конструкторе
    delegate( R foo(Args...)  )
        :mFunc(foo) 
    {} 
    
    R operator ()(Args&&... args)
    {
        // -- запуск функции
        return  mFunc( std::forward<Args>(args)...  );
    }
    
    pFunc mFunc;
};
 
 
int main()
{
    std::cout << "Hello, world!\n";
 
    
    // --- создаем делегат,
    // который нацелен на запуск функции foo
    delegate<int()> d = foo;
    
    // запускаем функцию foo опосредованно,
    // через делегат
    d();
}
в реальности делегаты учитывают множество самых различных нюансов,
что позволяет нацелить их куда угодно.
1
gng
644 / 490 / 133
Регистрация: 08.09.2013
Сообщений: 1,326
21.09.2015, 23:41 #44
Цитата Сообщение от daslex Посмотреть сообщение
только как если бы без typedef было не понимаю.
Не в тайпдефе дело. Если подпереться самым мощным костылем С++, коим является наследованная от Си низкоуровневость, можно и без него.
C++
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
 
void f (void (*_f)(void*)) {
  static int n= 2;
  std::cout << n << std::endl;
  if (--n) _f ((void*)f);
}
 
int main() {
  void (*pf)(void(*)(void*))= f;
  pf ((void(*)(void*))f);
}
В самой сишке с типизацией еще проще. Как сказали бы педанты, ещё большее раздолбайство, так что и без явного приведения обошлось. (во всяком случае, gcc и clang предупреждений не пишут).
C
1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
 
void f (void (*_f)()) {
  static int n= 2;
  printf ("%d\n", n);
  if (--n) _f (f);
}
 
int main() {
  void (*pf)(void(*)())= f;
  pf (f);
}
Без приведения типов в рамках указателей на функцию, как вам уже пояснили, задачу решить невозможно. Но ИМХО, Си++ со строгой типизацией - это уже не Плюсы.
1
hoggy
6636 / 2821 / 484
Регистрация: 15.11.2014
Сообщений: 6,240
Завершенные тесты: 1
21.09.2015, 23:50 #45
Цитата Сообщение от gng Посмотреть сообщение
void (*pf)(void(*)(void*))= f;
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
21.09.2015, 23:50
Привет! Вот еще темы с ответами:

Функция, получающая указатель на обычную функцию, получает указатель на метод класса - C++
Здравтсвуйте. Имеется вопрос по указателям на методы класса. Допустим, есть функция( f ), которая принимает указатель на функцию и...

Функция принимает указатель на void и возвращает указатель на int - C++
Запишите прототип функции, которая принимает указатель на void и возвращает указатель на int.

Указатель в списке ссылается на себя, а не на следующий элемент - C++
Уважаемые, форумчане! Помогите разобраться в вопросе. Я хочу реализовать стек(добавление элемента) на основе односвязного списка. ...

Деструктор для класс, имеющий указатель на самого себя - C++
Здравствуйте. Дан класс, для него нужно написать деструктор. using namespace std; class List{ private: int myValue; List...


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

Или воспользуйтесь поиском по форуму:
45
Yandex
Объявления
21.09.2015, 23:50
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru