выберите правильную специализацию шаблона во время выполнения - PullRequest
5 голосов
/ 11 апреля 2011

у меня

template <int i> struct a { static void f (); };

со специализациями в разных местах кода. Как я могу назвать правильный a<i>::f для i, известного только во время выполнения?

void f (int i) { a<i>::f (); } // won't compile

Я не хочу перечислять все возможные значения i в большом switch.

Edit:

Я думал о чем-то вроде

#include <iostream>

template <int i> struct a { static void f (); };

struct regf {
  typedef void (*F)();
  enum { arrsize = 10 };
  static F v[arrsize];
  template < int i > static int apply (F f) {
    static_assert (i < arrsize, "");
    v[i] = a<i>::f;
    return 0;
  }
};
regf::F regf::v[arrsize];

template <int i> struct reg { static int dummy; };
template <int i> int reg<i>::dummy = regf::apply<i> ();

void f (int i) { return regf::v[i] (); }

#define add(i) \
  template <> struct a<i> : reg<i> { \
    static void f () { std::cout << i << "\n"; } \
  };

add(1)
add(3)
add(5)
add(7)

int main () {
  f (3);
  f (5);
}

но он вылетает (я что-то упустил, чтобы вызвать инстанцирование?), И мне не нравится, что пустышка не static const (и использует память) и, конечно, что arrsize больше, чем необходимо. *


Актуальная проблема: иметь функцию generate (int i), которая вызывает a<i>::generate () для генерации экземпляра класса a<i> для i, заданного только во время выполнения. Дизайн (классы a<i>) дан, они наследуются от базового класса, и в любое время в любом месте кода может быть добавлено больше специализаций a, но я не хочу заставлять всех изменять мой generate (i) вручную, так как это можно легко забыть.

Ответы [ 5 ]

5 голосов
/ 11 апреля 2011

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

// in a single cpp file
namespace {
template <unsigned int N>
int register_a() {         // return artificially added
   register_a<N-1>();      // Initialize array from 0 to N-1
   regf::v[N] = &a<N>::f;  // and then N
   return N;
}
template <>
int register_a<0>() {
   regf::v[0] = &a<0>::f;  // recursion stop condition
   return 0;
}
const int ignored = register_a<regf::arrsize>(); // call it
}

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

Это весьма склонно к фиаско статической инициализации.Хотя regf::v в порядке, любой код, который зависит от regf::v, содержащий соответствующие указатели во время статической инициализации, обязательно завершится с ошибкой.Вы можете улучшить это с помощью обычных методов ...

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

4 голосов
/ 11 апреля 2011

Вы должны.Шаблоны разрешаются и создаются во время компиляции.Кроме того, switch не должен быть неэффективным.Обычно он компилируется в таблицу поиска с очень небольшими издержками.

Однако вы можете использовать рекурсивную магию шаблона, чтобы иметь вложенные блоки if/else для замены switch, сгенерированного для вас компилятором.Но простая switch должна быть намного более читаемой.Если, конечно, у вас есть буквально тысячи случаев.

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

2 голосов
/ 11 апреля 2011

Вы не можете выбрать специализацию шаблона во время выполнения, они по определению выбраны во время компиляции.

Обычные способы решения проблемы отправки, на которую вы смотрите: switch (как вы и предполагали) или vector или map из int для указателя функции.

1 голос
/ 11 апреля 2011

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

1 голос
/ 11 апреля 2011

Нет, компилятору необходимо создать экземпляр шаблона в время компиляции , для этого ему нужно знать значение i во время компиляции.

...