Re: char *(*(**foo[][8])())[]; - за сколько распарсите?
От: Shmj Ниоткуда  
Дата: 06.05.23 05:39
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Скажем, проинициализировать так — в корне char с значением 'a', а далее везде массивы с 1 элементом.


Кстати, это тоже интересно в качестве ребуса то.

"Всемогущий" GPT не осилил:

char* (*(**foo[][8])())[]; // объявление переменной foo

char* 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;

// использование foo
char** res = (*foo[0][0])(); // вызов функции, возвращающей arr1
printf("%s\n", res[1]); // печать "bar"
printf("%s\n", (*foo[1][0])[2]); // печать "three"


Вообще возможно ли это как-то инициализировать и вызвать?
Re[2]: char *(*(**foo[][8])())[]; - за сколько распарсите?
От: Нomunculus Россия  
Дата: 06.05.23 05:48
Оценка:
Здравствуйте, Shmj, Вы писали:

Помню в одном проекте у нас супер-умный чувак был, математик нехилый и вообще вундеркинд.
Так вот, у него была шиза — он всё… всё!!! ВСЁ писал через макросы.
То есть его программа выглядела так

int main()
{
MYSUPERMACROS1;
MYSUPERMARCOS2;
MYSUPERMWCROS3;
}

И эти макросы — это не просто однострочные коды — это охренеть какая сложная взаимосвязанная структура вложенных и зависимых других макросов

Не знай нафига он так делал. Чтоб свою незаменимость подчеркнуть и чтоб в его коде хрен кто после не разобрался?
Короче, с тех пор к нечитаемому коду испытываю жесткое отвращение. Это тупо неуважение к коллегам.

Твой код можно оформить гораздо читаемее. И нефиг извращаться.
Re[2]: char *(*(**foo[][8])())[]; - за сколько распарсите?
От: rg45 СССР  
Дата: 06.05.23 08:13
Оценка: 6 (1)
Здравствуйте, Shmj, Вы писали:

S>"Всемогущий" GPT не осилил:

S>Вообще возможно ли это как-то инициализировать и вызвать?

Да что ж вы такие беспомощные
Ну ладно Chat GPT, ей простительно — она маленькая девочка. Но ты-то — лоб здоровый, которому выше уже все разжевали — что не осилил опять?

http://coliru.stacked-crooked.com/a/ec19b1aaad28456c

#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нализ и использование foo

    using 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 ] }
{ }
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 06.05.2023 9:54 rg45 . Предыдущая версия . Еще …
Отредактировано 06.05.2023 8:33 rg45 . Предыдущая версия .
Отредактировано 06.05.2023 8:14 rg45 . Предыдущая версия .
Re[3]: char *(*(**foo[][8])())[]; - за сколько распарсите?
От: rg45 СССР  
Дата: 06.05.23 08:44
Оценка:
Здравствуйте, Нomunculus, Вы писали:

Н>Помню в одном проекте у нас супер-умный чувак был, математик нехилый и вообще вундеркинд.

Н>Так вот, у него была шиза — он всё… всё!!! ВСЁ писал через макросы.
Н>То есть его программа выглядела так

Н>int main()

Н>{
Н> MYSUPERMACROS1;
Н> MYSUPERMARCOS2;
Н> MYSUPERMWCROS3;
Н>}

Н>И эти макросы — это не просто однострочные коды — это охренеть какая сложная взаимосвязанная структура вложенных и зависимых других макросов


Н>Не знай нафига он так делал. Чтоб свою незаменимость подчеркнуть и чтоб в его коде хрен кто после не разобрался?


О, я тоже так писал когда-то Лет эдак 25 назад. Моя первая версия алгоритма А-звездочка так была написана. Почему на макросах? Ну чтоб не тратить драгоценные такты процессора на выполнение вызовов функций. Было такое мнение, что в потерях в производительности виноваты вызовы функций А еще я фукнцию извлечения квадратного корня писал на ассемблере, примерно в тот же период Я думаю, многие через это проходили. А некоторые так и застряли в том состоянии, судя по тому, что они тут пишут
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[4]: char *(*(**foo[][8])())[]; - за сколько распарсите?
От: Нomunculus Россия  
Дата: 06.05.23 08:49
Оценка: :)
Здравствуйте, rg45, Вы писали:

И как это дебажить?
Re[5]: char *(*(**foo[][8])())[]; - за сколько распарсите?
От: rg45 СССР  
Дата: 06.05.23 08:50
Оценка:
Здравствуйте, Нomunculus, Вы писали:

Н>И как это дебажить?


А никак Я же не призываю так делать, наоборот, сейчас смешно вспомнить.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 06.05.2023 8:50 rg45 . Предыдущая версия .
Re[3]: char *(*(**foo[][8])())[]; - за сколько распарсите?
От: Shmj Ниоткуда  
Дата: 07.05.23 00:45
Оценка:
Здравствуйте, rg45, Вы писали:

R>Ну ладно Chat GPT, ей простительно — она маленькая девочка. Но ты-то — лоб здоровый, которому выше уже все разжевали — что не осилил опять?


GTP такие вопросы по идее должны даваться легче, чем человеку. Для меня загадка почему он не справился.

В С++ много неочевидных моментов, связанных с декларированием сложных вещей. К примеру, пока не увидел какая сигнатура у функции, возвращающей указатель на другую функцию — никогда бы сам не догадался.

Этот пример многое раскрывает.
Re[3]: char *(*(**foo[][8])())[]; - за сколько распарсите?
От: Shmj Ниоткуда  
Дата: 07.05.23 00:49
Оценка:
Здравствуйте, Нomunculus, Вы писали:

Н>int main()

Н>{
Н> MYSUPERMACROS1;
Н> MYSUPERMARCOS2;
Н> MYSUPERMWCROS3;
Н>}

Н>И эти макросы — это не просто однострочные коды — это охренеть какая сложная взаимосвязанная структура вложенных и зависимых других макросов


Тут вопрос не чтобы так писать. А чтобы если кто-то уже написал, но хотя бы какие-то шансы были разораться в написанном.
Re[4]: char *(*(**foo[][8])())[]; - за сколько распарсите?
От: rg45 СССР  
Дата: 07.05.23 06:23
Оценка:
Здравствуйте, Shmj, Вы писали:


S>В С++ много неочевидных моментов, связанных с декларированием сложных вещей. К примеру, пока не увидел какая сигнатура у функции, возвращающей указатель на другую функцию — никогда бы сам не догадался.


Так я тебе для этого и показал выше
Автор: rg45
Дата: 20.04.23
, как разложить сложный тип на более простые:

    using A = char*[];
    using F = A*();
    using foo = F**[][8];


Если бы ты воспользовался этим подходом, то очень быстро у тебя все разложилось бы по полочкам. Но ты, как обычно, решил, что написанное не стоит твоего внимания. Да?
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[4]: char *(*(**foo[][8])())[]; - за сколько распарсите?
От: rg45 СССР  
Дата: 07.05.23 10:48
Оценка:
Здравствуйте, 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.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 07.05.2023 11:16 rg45 . Предыдущая версия . Еще …
Отредактировано 07.05.2023 11:03 rg45 . Предыдущая версия .
Отредактировано 07.05.2023 10:58 rg45 . Предыдущая версия .
Отредактировано 07.05.2023 10:56 rg45 . Предыдущая версия .
Отредактировано 07.05.2023 10:52 rg45 . Предыдущая версия .
Отредактировано 07.05.2023 10:49 rg45 . Предыдущая версия .
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.