Здравствуйте, Shmj, Вы писали:
S>Скажем, проинициализировать так — в корне char с значением 'a', а далее везде массивы с 1 элементом.
Кстати, это тоже интересно в качестве ребуса то.
"Всемогущий" GPT не осилил:
char* (*(**foo[][8])())[]; // объявление переменной foochar* arr1[] = {"foo", "bar", "baz"}; // пример массива строкchar* arr2[] = {"one", "two", "three", "four"}; // ещё один массив строк
// определение функции, возвращающей указатель на массив строкchar** func() {
return arr1;
}
// инициализация foo с помощью двух элементовchar* (*(*foo[2][8])())[] = {
{&func}, // первый элемент указывает на функцию, возвращающую arr1
{NULL} // второй элемент - нулевой указатель
};
// изменение второго элемента foo, чтобы он указывал на arr2
foo[1][0] = (char* (*(**)())[]) &arr2;
// использование foochar** res = (*foo[0][0])(); // вызов функции, возвращающей arr1
printf("%s\n", res[1]); // печать "bar"
printf("%s\n", (*foo[1][0])[2]); // печать "three"
Вообще возможно ли это как-то инициализировать и вызвать?
Re[2]: char *(*(**foo[][8])())[]; - за сколько распарсите?
Помню в одном проекте у нас супер-умный чувак был, математик нехилый и вообще вундеркинд.
Так вот, у него была шиза — он всё… всё!!! ВСЁ писал через макросы.
То есть его программа выглядела так
int main()
{
MYSUPERMACROS1;
MYSUPERMARCOS2;
MYSUPERMWCROS3;
}
И эти макросы — это не просто однострочные коды — это охренеть какая сложная взаимосвязанная структура вложенных и зависимых других макросов
Не знай нафига он так делал. Чтоб свою незаменимость подчеркнуть и чтоб в его коде хрен кто после не разобрался?
Короче, с тех пор к нечитаемому коду испытываю жесткое отвращение. Это тупо неуважение к коллегам.
Твой код можно оформить гораздо читаемее. И нефиг извращаться.
Re[2]: char *(*(**foo[][8])())[]; - за сколько распарсите?
Здравствуйте, Shmj, Вы писали:
S>"Всемогущий" GPT не осилил: S>Вообще возможно ли это как-то инициализировать и вызвать?
Да что ж вы такие беспомощные
Ну ладно Chat GPT, ей простительно — она маленькая девочка. Но ты-то — лоб здоровый, которому выше уже все разжевали — что не осилил опять?
#include <iostream>
const char* arr1[] = {"foo", "bar", "baz", nullptr}; // пример массива строкconst char* arr2[] = {"one", "two", "three", "four", nullptr}; // ещё один массив строк
// определение функций, возвращающих указатели на массивы строкconst char* (*func1())[] { return &arr1; }
const char* (*func2())[] { return &arr2; }
// определение указателей на функцииconst char* (*(*fptr1)())[] = &func1;
const char* (*(*fptr2)())[] = &func2;
int main()
{
// Инициализация foo - только не "с помощью двух элементов", а так, как это было в оригинальном варианте - массив произвольного размераconst char*(*(**foo[][8])())[] = {
{ &fptr1 }, // первый элемент указывает на функцию, возвращающую arr1
{ &fptr2 }, // второй элемент указывает на функцию, возвращающую arr2
{ &fptr1, &fptr2 }, // третий элемент указывает на две функции
{ &fptr1, &fptr2, &fptr1, &fptr2, &fptr1, &fptr2, &fptr1, &fptr2 }, // четвертый элемент тоже на что-то указывает
{ }, // пятый элемент - пустой (содержит восемь nullptr)
};
// Aнализ и использование foousing String = const char*;
using ArrayOfString = String[];
using Function = ArrayOfString*();
for (Function** (&afpp)[8] : foo)
{
std::cout << "{ ";
for (Function** fpp : afpp)
{
if (fpp)
{
if (Function* fp = *fpp)
{
if (ArrayOfString* asptr = fp())
{
std::cout << "[ ";
for (const String* s = *asptr; *s; ++s)
{
std::cout << *s << ' ';
}
std::cout << "] ";
}
}
}
}
std::cout << "}" << std::endl;
}
}
g++ -std=c++20 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
{ [ foo bar baz ] }
{ [ one two three four ] }
{ [ foo bar baz ] [ one two three four ] }
{ [ foo bar baz ] [ one two three four ] [ foo bar baz ] [ one two three four ] [ foo bar baz ] [ one two three four ] [ foo bar baz ] [ one two three four ] }
{ }
Здравствуйте, Нomunculus, Вы писали:
Н>Помню в одном проекте у нас супер-умный чувак был, математик нехилый и вообще вундеркинд. Н>Так вот, у него была шиза — он всё… всё!!! ВСЁ писал через макросы. Н>То есть его программа выглядела так
Н>int main() Н>{ Н> MYSUPERMACROS1; Н> MYSUPERMARCOS2; Н> MYSUPERMWCROS3; Н>}
Н>И эти макросы — это не просто однострочные коды — это охренеть какая сложная взаимосвязанная структура вложенных и зависимых других макросов
Н>Не знай нафига он так делал. Чтоб свою незаменимость подчеркнуть и чтоб в его коде хрен кто после не разобрался?
О, я тоже так писал когда-то Лет эдак 25 назад. Моя первая версия алгоритма А-звездочка так была написана. Почему на макросах? Ну чтоб не тратить драгоценные такты процессора на выполнение вызовов функций. Было такое мнение, что в потерях в производительности виноваты вызовы функций А еще я фукнцию извлечения квадратного корня писал на ассемблере, примерно в тот же период Я думаю, многие через это проходили. А некоторые так и застряли в том состоянии, судя по тому, что они тут пишут
--
Re[4]: char *(*(**foo[][8])())[]; - за сколько распарсите?
Здравствуйте, rg45, Вы писали:
R>Ну ладно Chat GPT, ей простительно — она маленькая девочка. Но ты-то — лоб здоровый, которому выше уже все разжевали — что не осилил опять?
GTP такие вопросы по идее должны даваться легче, чем человеку. Для меня загадка почему он не справился.
В С++ много неочевидных моментов, связанных с декларированием сложных вещей. К примеру, пока не увидел какая сигнатура у функции, возвращающей указатель на другую функцию — никогда бы сам не догадался.
Этот пример многое раскрывает.
Re[3]: char *(*(**foo[][8])())[]; - за сколько распарсите?
Здравствуйте, Нomunculus, Вы писали:
Н>int main() Н>{ Н> MYSUPERMACROS1; Н> MYSUPERMARCOS2; Н> MYSUPERMWCROS3; Н>}
Н>И эти макросы — это не просто однострочные коды — это охренеть какая сложная взаимосвязанная структура вложенных и зависимых других макросов
Тут вопрос не чтобы так писать. А чтобы если кто-то уже написал, но хотя бы какие-то шансы были разораться в написанном.
Re[4]: char *(*(**foo[][8])())[]; - за сколько распарсите?
S>В С++ много неочевидных моментов, связанных с декларированием сложных вещей. К примеру, пока не увидел какая сигнатура у функции, возвращающей указатель на другую функцию — никогда бы сам не догадался.
using A = char*[];
using F = A*();
using foo = F**[][8];
Если бы ты воспользовался этим подходом, то очень быстро у тебя все разложилось бы по полочкам. Но ты, как обычно, решил, что написанное не стоит твоего внимания. Да?
--
Re[4]: char *(*(**foo[][8])())[]; - за сколько распарсите?
Здравствуйте, Shmj, Вы писали:
S>В С++ много неочевидных моментов, связанных с декларированием сложных вещей. К примеру, пока не увидел какая сигнатура у функции, возвращающей указатель на другую функцию — никогда бы сам не догадался.
На самом деле, ничего особенно сложного нет, нужно знать лишь пару несложных принципов. Первое, что нужно знать — результатом функции не может быть другая функция или массив, но результатом может быть указатель на функцию или массив. Второе, что нужно знать — для того, чтобы объявить указатель на функцию или массив, нужно использовать дополнительные круглые скобки, которыми мы как-бы присоединим символ указателя к имени массива или функции. Без этих дополнтительных круглых скобок символ указателя будет относиться либо к результату функции, либо к элементу массива.
Конструирование сложного объявления проще всего выполнять последовательно, добавляя новые синтаксические элементы непосредственно слева или справа от имени. Например, имеем изначально простое объявление:
Функция, принимающая строку и возвращающая число:
int foo(const char*);
Указатель на функцию, принимающую строку и возвращающую число (используем дополнительные круглые скобки):
int (*foo)(const char*);
Массив указателей на функции принимающие строку, и возвращающие число (добавляем квадратные скобки с размерностью массива сразу справа от имени):
int (*foo[42])(const char*);
Указатель на массив указателей на функции принимающие строку, и возвращающие число (опять используем дополнительные круглые скобки)
int (*(*foo)[42])(const char*);
Функция, принимающая double, возвращающая указатель на массив указателей на функции принимающие строку, и возвращающие число
(просто добавляем справа от имени декларации список формальных параметров в круглых скобках):
int (*(*foo(double))[42])(const char*);
Указатель на функцию, принимающую double, возвращающую указатель на массив указателей на функции принимающие строку, и возвращающие число
int (*(*(*foo)(double))[42])(const char*);
Анализ выполняется в обратном порядке, начиная от имени объявления.
Сложнее всего, когда имя в объявлении опущено и найти его не всегда просто:
using FooPtr = int (*(*(*)(double))[42])(const char*);
Тут уже нужно иметь некоторую сноровку, чтобы быстро находить точку отсчета, от которой следует проводить разбор.
Но на практике таких многоэтажных объявлений лучше вообще избегать, используя using или typedef.