Объявление ссылки на пространство имен во время выполнения в C ++ - PullRequest
0 голосов
/ 14 мая 2018

У меня есть программа на С ++, в которой я:

  1. Иметь класс, который содержит в качестве членов дескрипторы функций, скажем, void (*foo) и void (*bar)
  2. Иметь набор пространств имен, каждое из которых определяет функции с одинаковыми именами, например:
    • namespace1 содержит функции void foo() и void bar()
    • namespace2 также содержит функции void foo() и void bar()

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

В настоящее время я использую что-то вроде следующего:

 if (choice == "namespace1") {
     my_class.foo = &(namespace1::foo);
     my_class.bar = &(namespace1::bar);
 } else if (choice == "namespace2") {
     my_class.foo = &(namespace2::foo);
     my_class.bar = &(namespace2::bar);
 }

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

Есть ли способы, которыми я могу привести это в порядок? Моей первой мыслью было что-то вроде:

 if (choice == "namespace1") {
     my_namespace = namespace1;
 } else if (choice == "namespace2") {
     my_namespace = namespace2;
 }
 my_class.foo = &(my_namespace::foo);
 my_class.bar = &(my_namespace::bar);

Но, если я правильно понимаю, я не могу использовать пространства имен в качестве переменных.

Есть ли лучший способ сформулировать это? Как это структурировано, это плохой стиль и есть ли более стандартный способ сделать это?

Спасибо за ваши идеи!

Ответы [ 3 ]

0 голосов
/ 14 мая 2018

Я предлагаю использовать черты.

template<Context C>
struct context;

template<NAMESPACE_1> struct context<> {
  static foo_return_t foo(...) {
    return namespace1::foo (...);
  }
  static bar_return_t bar(...) {
    return namespace1::bar (...);
  }
};

template<NAMESPACE_2> struct context<> {
  static foo_return_t foo(...) {
    return namespace2::foo (...);
  }
  static bar_return_t bar(...) {
    return namespace2::bar (...);
  }
};

Затем используйте так:

foo_ret_t a;
bar_ret_t b; 

if (choice == "namespace1") {
  a = context<NAMESPACE_1>::foo(...);
  b = context<NAMESPACE_1>::bar(...);
} else if (choice == "namespace1") {
  a = context<NAMESPACE_2>::foo(...);
  b = context<NAMESPACE_2>::bar(...);
}

Ваша проблема в том, что материал оценивается во время выполнения.

0 голосов
/ 14 мая 2018

Расширить на ответ @ MSalters ...

Существует шаблон проектирования, который решает эту ситуацию. Он называется Шаблон внедрения зависимости .

Ваш класс (где вы пытаетесь хранить foo и bar) - это клиент.

Пространства имен содержат классы, которые реализуют интерфейс.

Инжектор зависимостей должен будет внедрить зависимость (указатель на один из конкретных классов в пространствах имен) в клиент.

0 голосов
/ 14 мая 2018

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

Стандартным решением является определение интерфейса .

class IFooBar {
   virtual void foo() = 0;
   virtual void bar() = 0;
   // Other 7 functions.
};

Это позволяет каждому пространству имен определять один класс вместо 9 функций.

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

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