LINUX.ORG.RU

Функция, возвращающая указатель на функцию такого же типа

 , ,


0

3

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

Вариант

typedef funct * (*funct)(void);
не работает.

★★★★★
Ответ на: :) от Stil

В тип функции, возвращающий void *. Например

void *bar(void);

void *foo(void)
{
  return (void *)bar;
}

int main(void)
{
  void *ptr = (*(void *(*)()) foo())();
}

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

foo() вернет указатель на bar()

(*(void *(*)()) foo())() вернет указатель туда же, куда вернет bar().

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

Ну я объявил функцию bar(). Определить ее можно в другом .c файле, и потом слинковать объектные файлы. См. http://cppstudio.com/post/2647/

Вызов функции bar() скомпилируется нормально

SZT ★★★★★
() автор топика

Указатель на void можно приводить к указателю любого другого типа; это разрешено и не приводит к каким-либо проблемам.

Deleted
()
Ответ на: комментарий от SZT

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

mittorn ★★★★★
()

Ты бы ещё про комбинаторы на с спросил

anonymous
()

пусть она у тебя возвращает указатель на void, это нормально, не требуется даже каст типов:

typedef void* (*FuncP_t)(void);

void *test_f(void)
{
	printf(" hello world\n");
	FuncP_t ret = test_f;
	return ret;
}

int main(void)
{
	FuncP_t myfp = test_f();
	myfp();
	return 0;
}

компилируется с Wall без ошибок

IvanR ★★★
()
Последнее исправление: IvanR (всего исправлений: 1)
Ответ на: комментарий от Deleted

Указатель на void можно приводить к указателю любого другого типа; это разрешено и не приводит к каким-либо проблемам.

Да-да, ни к каким проблемам! А типизацию придумали трусы.

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

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

Да и тут в принципе невозможна типизация - тут рекурсивное вложение.

TrueTsar1C
()
Ответ на: комментарий от SZT

В C походу только void указатели остается кастовать в нужный тип

И не в си так же.

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

В си это void * - вперёд:

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

Тебе надо на каком-то шаге стопнуть рекурсию приведя указатель к общему типа.

В чем смысл твой проблемы я так и не понял - нахрена это может быть нужно?

TrueTsar1C
()
Ответ на: комментарий от mittorn

Си не годится для метапрограммирования, даже такого примитивного

Пример юзкейса такого «примитивного» можно?

А так же юзкейс «метапрограммирования» в студию, ваще любого, если по теме не осилишь.

TrueTsar1C
()

В C нельзя. В C++ можно через свой тип и перегрузку операторов.

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

Это в сишечке. Другие языки справятся с такой типизацией.

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

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

Тебе надо на каком-то шаге стопнуть рекурсию приведя указатель к общему типа.

Как-то так:

struct my_fun_type {
    ...

    my_fun_type operator()(/*...*/);

    ...

};
Возвращать можно и по указателю(или через умные указатели), а так же по ссылке.

anonymous
()
Ответ на: комментарий от SZT
#include <iostream>

using namespace std;

class MyFooHelper;
typedef MyFooHelper (*MyFoo)();

class MyFooHelper {
public:
	MyFooHelper(MyFoo p) : mFoo(p) {}
	operator MyFoo() const { return mFoo; }
private:
	MyFoo mFoo;
};

MyFooHelper first();
MyFooHelper second();
MyFooHelper third();

MyFooHelper first() {
	cout << "first() called" << endl;
	return second;
}

MyFooHelper second() {
	cout << "second() called" << endl;
	return third;
}

MyFooHelper third() {
	cout << "third() called" << endl;
	return first;
}

int main() {
	MyFoo f = first;

	while (true) {
		f = f();
		getchar();
	}
}

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

Как-то так:

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

Это делается и в сишке, только ещё раз - это не возврат указателя на функцию того же типа. Это эмуляция, тоже самое, что и через воид.

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

1. Понты
2. Иногда в линейном виде исходник громоздкий и его можно сгенерировать конечным циклом, но это скорее ближе к макросам, чем полноценной кодогенерации.

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

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

В си это void * - вперёд:

шо за привычка такая: зайти в первый попавшийся тред с тегом «с» и тут же обосраться?

согласно с99, указатель на функцию даже не обязан иметь размер равный размеру void *

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

Это не костыль. Нормальный код. И скорее всего он делает то, что нужно ТС. Просто ТС об этом способе не знал. Потому и спросил про указатели. У C++ чуть более развитая система типов, чем у С. Можно ещё вспомнить, что на Си нельзя написать функцию, которая бы корректно возвращала результат разыменования указателя без потери возможности записи туда.

/* непонятно какой тип*/
foo()
{
    ...
    return *p;
}
anonymous
()
Ответ на: комментарий от anonymous

согласно с99, указатель на функцию даже не обязан иметь размер равный размеру void *

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

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

шо за привычка такая: зайти в первый попавшийся тред с тегом «с» и тут же обосраться?

Ну и?

согласно с99, указатель на функцию даже не обязан иметь размер равный размеру void *

Меня мало интересуют проблемы всякого говна, если хочешь жрать говно - дорисуй туда 2скобочки.

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

Это не костыль.

Кастыль. Меня не интересует нормальный он или не нормально - он противоречит условию.

И скорее всего он делает то, что нужно ТС. Просто ТС об этом способе не знал.

Естественно он делает то, что нужно тс"у, ибо то, что нужно ТС"у невозможно.

У C++ чуть более развитая система типов, чем у С

Что значит развитая?

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

Щито?

TrueTsar1C
()
Ответ на: комментарий от nezamudich

и правильно не нашёл. 6.2.5.27 начинается со следующего предложения: «A pointer to void shall have the same representation and alignment requirements as a pointer to a character type». дальше идёт про то что указатели на встроенные типы должны быть такими же. указатели на структуры должны быть совместимы между собой; то же самое про объединение. в конце ВНЕЗАПНО: «Pointers to other types need not have the same representation or alignment requirements».

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

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

Меня мало интересуют проблемы всякого говна, если хочешь жрать говно

хочу кормить говном тебя. не знаешь что такое void *, а кукарекаешь.

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

это только тебе непонятно какой тип. там будет int.

int
foo()
{
    ...

    int *p;

    ...
    return *p;
}

Так? Не работает:

foo() = 10;

Читай внимательнее.

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

он противоречит условию.

Это должен решить ТС.

Щито?

Ну смотри. В Си я могу написать так: *p = 10. Но не могу написать функцию, которая бы возвращала результат *p и при этом позволяла мне так же записывать туда данные: foo() = 10. И все потому, что тип результа *p полностью в Си не выразить. В C++ operator * возвращает ссылку.

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

Ну используй void (*)() вместо простого void*. Тогда будет по стандарту.

anonymous
()

хочу кормить говном тебя. не знаешь что такое void *, а кукарекаешь.

Кого ты там покормишь. Что конкретно я не знаю?

Ты пока давай, высирай цитатки про длину воид.

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

Это должен решить ТС.

С чего это?

Ну смотри. В Си я могу написать так: *p = 10.

И?

Но не могу написать функцию, которая бы возвращала результат *p

С чего?

и при этом позволяла мне так же записывать туда данные: foo() = 10

Куда туда?

И все потому, что тип результа *p полностью в Си не выразить.

Что?

В C++ operator * возвращает ссылку.

Какие нахрен операторы, какие нахрен ссылки. Ты мне конкретный пример выкати, а то слушать твою несвязную херню утомительно.

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

Так? Не работает:

Ты аутист чтоли? С какого хрена это должно работать?

int foo(void) {
  int *p = &(int){0};
  return *p;
}

Читай внимательнее.

И что он должен был тут прочитать?

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

С чего это?

Потому, что он задал вопрос. И он решает, удовлетворяет ли его предложенное решение.

Куда туда?

Туда, куда указывал указатель.

Какие нахрен операторы, какие нахрен ссылки. Ты мне конкретный пример выкати, а то слушать твою несвязную херню утомительно.

Вот пример на C++:

int & foo()
{
    ...
    return *p;
}

*p = 10;    // ok
foo() = 10; // ok
anonymous
()
Ответ на: комментарий от anonymous

без потери возможности записи

Ну прочитал он и её, а что она ему дала? Мне ничего не дала.

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

Толку с этого?

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

Вот пример на C++:

Ты мне весь код давай, а не неведомую херню.

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

Потому, что он задал вопрос. И он решает, удовлетворяет ли его предложенное решение.

Нет, есть конкретное описание задачи и есть решение этой самой задачи. ТС к ней не имеет никакого отношения.

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

Что тут непонятного-то? Давай так попробуем

#define foo(p) (*p)
Как мне это сделать в виде функции?

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

без потери возможности записи

я это проинтерпретировал как отсутствие гарантии правильного выравнивания при касте к void *

такой травы как у тебя у меня, увы, нет

// тот самый анонимус

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