std :: type_info для массива определенной длины во время выполнения - PullRequest
3 голосов
/ 04 апреля 2020

При использовании typeid(char[10]) каждый получает std::type_info для char[10].

Теперь у меня есть проблема, которую мне нужно получить typeid(char[n]), где n не constexpr.

Есть ли способ сделать это?

Моя текущая реализация просто использует шаблоны рекурсивным способом для генерации вызовов от typeid(char[1]) до typeid(char[100]) и затем выбирает правильный вызов с рекурсивной функцией это останавливается на правильном номере.

Хотя это работает, оно работает только до 100, и если я увеличу его намного выше, оно сгенерирует много кода или прекратит компиляцию из-за слишком глубокой рекурсии

Есть ли другие возможности?

Наивная реализация, которая будет делать то, что я хочу:

const std::type_info& getTypeInfoForCharArray(size_t len) 
{
  switch(len) 
  { 
    case 1: return typeid(char[1]);
    case 2: return typeid(char[2])
    case 3: return typeid(char[3])
    case 4: return typeid(char[4])
   ... 
  } 
} 

Фон

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

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

Если ответ на мой вопрос «нет, этого нельзя сделать», то мне просто придется обращаться с массивами иначе, чем с другими типами.

1 Ответ

1 голос
/ 04 апреля 2020

Вы можете использовать std::integer_sequence:

template <typename T>
struct Helper;

template <std::size_t ...L>
struct Helper<std::integer_sequence<std::size_t, L...>> {
    static const std::type_info &get(std::size_t len) {
        static const std::type_info *a[sizeof...(L)] = {&typeid(char[L])...};
        return *a[len];
    }
};

const std::type_info &getTypeInfoForCharArray(std::size_t len) {
    const std::size_t max = 10000;
    assert(len<=max);
    return Helper<std::make_integer_sequence<std::size_t, max+1>>::get(len);
}

int main() {
    auto &t = getTypeInfoForCharArray(10000);
    std::cout << t.name() << "\n";
}

Это компилируется за ~ 1 секунду с Clang (с max размером 10000).

Обратите внимание, что это решение будет генерировать все объекты type_info от 0 до max, которым может потребоваться значительный объем данных (для этого примера результирующий двоичный файл равен ~ 1 МБ), поскольку компилятору необходимо сгенерировать все объекты type_info в двоичный файл.

Я думаю, что если у вас нет списка возможных размеров заранее, это лучшее, что вы можете сделать (или, возможно, вы можете рассмотреть какое-то решение, зависящее от компилятора. Например, использовать тот факт, что мы знаем о формате type_info::name(), но это хакерское решение. Но, может быть, это нормально, если вы используете эту функцию только для отладки).

...