Шаблони C ++ для доступу до масивів різного розміру елементів?

Як я можу використовувати шаблони C ++, щоб виконати наступне, чи є якийсь кращий спосіб?

У моїх pgm міститься ряд великих, простих таблиць. Для економії місця кожен таблицю може бути символом, коротким, довгим або довгим (тобто, записи з 8, 16, 32 або 64 бітами у моєму компіляторі, VS2010) залежно від вмісту таблиці (таблиці побудовані один раз на початку pgm). У мене є функції, які працюють на цих таблицях, і я хотів би написати єдину функцію, яка обробляє всі типи.

Таблиці виділяються за допомогою нових. Спрощена версія для ілюстрації:

struct S1 {char x;}
struct S2 {short x;};
struct S4 {long x;}
struct S8 {long long x;};
struct V {int n; void *v};//n=1,2,4 or 8, and v points to an array of Sn

V.v=new Sn[arrayLength];//Sn is one of S1, S2, S4 or S8

Проблема виникає, коли я хочу отримати доступ до елементу масиву, використовуючи v [i], тому що розмір елемента масиву невідомий під час компіляції. Схоже, що шаблони повинні дозволити це зробити, але я не маю досвіду з ними.

Щоб розробити, включивши пропозицію Crazy Eddie, зараз мій код виглядає так

У VA.h:

class VA
{
    struct S1 {char x;}
    struct S2 {short x;};
    struct S4 {long x;}
    struct S8 {long long x;};
    template < typename T>
    struct V {int n; T *v};//n=1,2,4 or 8, and v points to an array of Sn

    V vTable[1000];//a fixed array size

    void Func1(int k, int n, int size);
};

У VA.cpp:

void Func1(int k, int n, int size)
{
    V *pV=&vTable[k];//Question 1: How do I get from n to the appropriate type T?
    pV->n=n;
    pV->v=new SOMETHING[size];//Question 2: What should SOMETHING be here?
                              //I am allocating an array of Sn
    ...
1
Подумайте про використання бібліотеки
додано Автор medivh, джерело

6 Відповіді

Ні, шаблони не допоможуть вирішити проблему, яку ви створили, використовуючи void * . Введення інформації відсутнє. Компілятор знає лише void * і має нульову інформацію про розмір компонента позаду нього.

Якщо ж, з іншого боку, ви використовували шаблони, щоб почати з вас, не виникне ця проблема:

template < typename T >
struct V { int n; T * v; };
2
додано
Це не дозволило б йому мати єдину структуру, щоб тримати всі різні структури, хоча ...
додано Автор csteifel, джерело
За допомогою цього визначення ви можете використовувати V та ін як типи. Ви також можете писати функції шаблонів, декларації яких починаються з template , які роблять об'єкти загальними V об'єктами.
додано Автор aschepler, джерело
Це виглядає так, як я хочу. Чи можете ви трохи розібратися? Якщо я зараз хочу функцію в класі, що містить V, як мені передати це фактичне ім'я типу? І яка синтаксис для "нового" виділення?
додано Автор Woody20, джерело
Перегляньте додаткові подробиці та питання, додані до мого першого повідомлення
додано Автор Woody20, джерело

Замість цього можна використовувати союз.

Робіть щось подібне

union unionType {
  char a;
  int b;
  long long c;
};

Now this will allow you to just specify the array type as the union. The problem with this is you may wind up with a bunch of wasted memory because of padding that is inserted by the union. You may also have to Робіть щось подібне to keep track of the type:

struct arrayType {
   int type; //Something like 0-char, 1-short, 2-long, etc...
   unionType value;
};

struct arrayType {
  int length;
  arrayType v;
}

For more information on unions I actually quite like the wikipedia page on them: http://en.wikipedia.org/wiki/Union_type

1
додано
Я пропоную це просто як спосіб зробити це без використання зовнішніх бібліотек, таких як підвищення.
додано Автор csteifel, джерело
-1 Він спеціально сказав, що робить це, щоб заощадити місце, і ваше рішення його витрачає.
додано Автор Kleist, джерело
Немає потреби в зовнішніх бібліотеках, див. Відповідь Crazy Eddie.
додано Автор Kleist, джерело
Клейст правильний. Ці таблиці величезні, і єдиною точкою різного типу є економія місця.
додано Автор Woody20, джерело

Щоб відповісти на оновлені питання:

  1. Ви використовуєте перемикач:
template
void Func1(int k, int size)
{
    V *pV=&vTable[k];
   //No need for pv->n; just call sizeof(T).
    pV->v=new Sn[size];
}

void Func1(int k, int n, int size)
{
  switch (n) {
    case 1: Func1(k, size);
    case 2: Func1(k, size);
   //...
  }
}

Mind you, when you know n at compile time, you can call Func1 directly. Also, be aware that V is a class template, not a class. V is a class. You therefore cannot have an array of V's, but you can have an array of V.

0
додано
@ Woody20: Я думаю, що аналізатор розмітки з'їв мій
додано Автор MSalters, джерело
MSalters, у вашому відповідь, ваш "шаблон void Func1" не має вказівки для компілятора, що таке клас шаблону або тип. Що мені не вистачає? І я не бачу, як "новий Sn" замінюватиметься "новими S1", "новими S2" тощо (там немає типу "Sn", це просто моя стенографія для "одного з S").
додано Автор Woody20, джерело

Можливо, вам буде кращий сервер, написавши "примітивний" контейнер .. (або навіть використовувати стандартний.)
Якщо ви пишете себе, дизайн std :: array - це те, що вам слід намагатись скопіювати, якщо вам не потрібно, щоб розмір був динамічним.

template
class array
{
public:
    //....Constructors..etc
private:
    T* data;
}

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

0
додано

Замість того, щоб писати свій власний шаблон, чому б не використовувати бібліотеку шаблонів?

Boost :: Variant або Boost :: Будь-який може вам допомогти. Вони були розроблені спеціально для певної проблеми, що у вас є.

See: boost::variant conversion to type

0
додано
@ Woody20: Ні, часто стандартні функції шаблону бібліотеки настільки ж швидко, як і спеціальний код, або краще.
додано Автор aschepler, джерело
@ Woody20: це не звичайна бібліотека, це бібліотека шаблонів! Об'єкти, створені з шаблонів, спеціально розроблені для вказаних типів, отже, вони є просторовими та тимчасовими, у порівнянні з тим, як шаблони не використовувались. Бібліотеки Boost також рецензовані перед включенням. Крім того, для вашої справи, якщо ви, наприклад, сумуєте всі елементи масиву і хочете їх роздруковувати, вам слід знати, чи слід використовувати модифікатор "% c" або "% d" або "% lu" для printf. Таким чином, вона повинна бути адаптована до конкретного типу. Для цього інтерфейс відвідувача Boost :: Variant є ідеальним.
додано Автор ruben2020, джерело
Хоча я і не згадав про це, швидкість також важлива. Я підозрюю, що бібліотека шаблонів набагато менш ефективна, ніж користувацький код C ++.
додано Автор Woody20, джерело

Якщо я правильно зрозумів ваші вимоги, то, можливо, захочете подивитися в векторну бібліотеку. Наприклад:

#include 

std::vector V;

V - це динамічний список, елементи якого мають 1 символ.

0
додано
IT KPI C/С++ новым годом
IT KPI C/С++ новым годом
747 учасників

Чат обсуждения С/С++. - Вопросы "напишите за меня лабу" - это оффтоп. - Оффтоп, флуд, оскорбления и вбросы здесь не приняты. - За нарушение - предупреждение или mute на неделю. - За спам и рекламу - ban. Все чаты IT KPI: https://t.me/itkpi/1147