LINUX.ORG.RU

c++ вызов функций по строковым именам

 ,


1

5

Дано:

if("FUNCTION1")
  FUNCTION1();
else if("FUNCTION2")
  FUNCTION2();
...
else if("FUNCTION100")
  FUNCTION100();

Собственно быдлокод же. Дерево сравнений не выровнено, одно и тоже пишется по сто раз...

А как красиво и без около хаковских штучек рантайма?

★★★★★

Желательно подробнее задачу сформулировать. Навскидку - завести map <имя, функция>.

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

Понятно что это уберёт проблему с не сбалансированным деревом сравнений. Ну так надо заводить map из 100 элементов

(«function1», &function1()), ..., («function100», &function100())

Тоже такая КЭПская портянка ого-го размером.

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

map<string, function<void(void)>> например.

invy ★★★★★ ()

dlsym или

#define CALL_FUNC( name ) else if( #name ) name();

if( 0 )
CALL_FUNC( FUNCTION1 )
CALL_FUNC( FUNCTION2 )
CALL_FUNC( FUNCTION3 )
anonymous ()

И зачем оно? Не пойму.

FIL ★★★★ ()
#include <stdio.h>

typedef void(*Foo1)();

void foo1Impl()
{
  printf("foo1\n");
}

typedef void(*Foo2)(int);

void foo2Impl(int val)
{
  printf("foo2 %d\n", val);
}

int main()
{

// .....
   Foo1 foo1 = foo1Impl;
   Foo2 foo2 = foo2Impl;

// .....

   if(foo1)
     foo1();
   if(foo2)
     foo2(10);

   return 0;
}
andreyu ★★★★★ ()
Ответ на: комментарий от fornlr

Тоже такая КЭПская портянка ого-го размером.

Ну как бонус, возможность непрямого соответствия между «именем» и функцией. Потому и поинтересовался зачем оно нужно. Задача ведь не в вакууме возникла?

DarkEld3r ★★★★★ ()

Какой-нибудь hashmap заюзай. Не знаю что у вас там в stl.

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

Ну так надо заводить map из 100 элементов

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

matrixd ()

Можно писать просто короче

if (name == "function2") return &FUNCTION2;
Если так тоже не хочется делать, то можно строить статические хеш таблицы, напричер через gperf

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

Можно сделать красиво через re2c, и работать будет за О(1)

annulen ★★★★★ ()
Последнее исправление: annulen (всего исправлений: 1)
#include <functional>
#include <iostream>
#include <map>
#include <string>
#include <utility>

namespace {
    template <typename R, typename... Args>
    struct FunCat
    {
        typedef R RType;

        typedef std::map<std::string, std::function<R(Args...)> > FunMap;

        static FunMap &get_fun_map()
        {
            static FunMap fun_map;
            return fun_map;
        }

        FunCat(const std::string &name, const std::function<R(Args...)> &function)
        {
            get_fun_map()[name] = function;
        }

        static R call_by_name(const std::string &name, Args&&... args)
        {
            return get_fun_map()[name](std::forward<Args>(args)...);
        }
    };

    typedef FunCat<void, int, int> SimpleFunCat;
}

#define defun(cat, name, args) \
    cat::RType name args; \
    namespace { cat register_function_ ## name ## _in_ ## cat(#name, name); } \
    cat::RType name args

defun(SimpleFunCat, fun1, (int param1, int param2))
{
    std::cout << "fun1 called with param1 == " << param1 << " and param2 == " << param2 << "\n";
}

defun(SimpleFunCat, fun2, (int param1, int param2))
{
    std::cout << "fun2 called with param1 == " << param1 << " and param2 == " << param2 << "\n";
}

int main()
{
    SimpleFunCat::call_by_name("fun1", 123, 456);
    SimpleFunCat::call_by_name("fun2", 654, 321);

    return 0;
}
mironov_ivan ★★★★★ ()

Я бы сделал одно из двух:
- сделал парсер кода, который бы мне вот такое создавал
либо
- в начало каждой функции вставлял строчку, которая бы добавляла __FUNCTION__ (или __func__) в какой-нибудь глобальный std::map (скорее всего она везде одинакова будет).

Но вообще-то разарботка с использованием компилируемых ЯП такого не предполагает.

Может приведешь суть задачи, которую ты пытаешься решить подобным образом?

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

- в начало каждой функции вставлял строчку, которая бы добавляла __FUNCTION__ (или __func__) в какой-нибудь глобальный std::map (скорее всего она везде одинакова будет).

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

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

Тоже такая КЭПская портянка ого-го размером.

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

no-such-file ★★★★★ ()
Ответ на: комментарий от mironov_ivan

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

Блин, не подумал. Согласен.
Тогда макрос, который 1) вне функции ддобавляет в map 2) открывает функцию. Так будет работать. (Соответственно, имя функции - аргумент макроса).

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

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

Ivana ()

Запил JIT-компиляции через llvm — не около хаковских штучек рантайма?

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

зачем? вместо функции  — лямбду. пусть сразу внутри массива инициализируется.

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

- в начало каждой функции вставлял строчку, которая бы добавляла __FUNCTION__ (или __func__) в какой-нибудь глобальный std::map (скорее всего она везде одинакова будет).

имя функции она вставит в строковом виде, но не адрес и будет бесполезна

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

Получать список функций из таблиц символов компилятора. Код генерировать. Ну или какой-то парсер, чтобы не привязываться к toolchain. В ++ можно делать вызовы в global scope, так что создать макрос с помощью которого объявлять необходимые в списке функции. А без ++ можно складывать переменные в отдельную секцию.

Достаточно легкое решение мне было бы тоже интересно.

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