2014-09-30 3 views
4

У меня есть назначение, которое просит написать функцию для любого типа данных. Предполагается, что функция должна печатать байты структуры и идентифицировать общее количество байт, которые использует структура данных, и дифференцировать байты, используемые для членов и используемых байтов для заполнения.Функция C++, которая принимает любой тип данных без использования шаблонов?

Моей непосредственной реакцией, наряду с большинством реакций классов, было использование шаблонов. Это позволяет вам написать функцию один раз и собрать тип времени выполнения объектов, переданных в функцию. Используя memset и typeid, вы можете легко выполнить то, что было задано. Однако наш проф. просто увидели наше обсуждение шаблонов и проклятых шаблонов в ад.

Увидев это, меня бросили в петлю, и я ищу небольшое руководство, как лучший способ обойти это. Некоторые вещи, которые я посмотрел на:

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

Я надеялся, что я упустил из виду общий инструмент C++, есть ли у кого-нибудь идеи?

+16

Если ваш ** C++ ** инструктор проклят шаблонами в ад, я искренне надеюсь, что еще не поздно отказаться от занятий для другого преподавателя. Конечно, что-то должно быть проклято в ад, но это не шаблоны. – WhozCraig

+3

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

+0

Что именно вы задали? Рассеять необработанную память структуры на член и байты заполнения? –

ответ

1

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

параметры функции:

  • Структура адреса, как uint8_t *. (Необходимо напечатать байты)
  • Размер структуры в байтах. (Необходимо распечатать байты и распечатать общий размер)
  • Вектор информации о членах: длина члена ИЛИ сумма байтов, используемых членами.

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

Пример:

void Analyze_Structure(uint8_t const * p_structure, 
         size_t   size_of_structure, 
         size_t   size_occupied_by_members); 

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

Надеюсь, это поможет.

Edit 1:

struct Apple 
{ 
    char a; 
    int  weight; 
    double protein_per_gram; 
}; 

int main(void) 
{ 
    Apple granny_smith; 
    Analyze_Structure((uint8_t *) &granny_smith, 
        sizeof(Apple), 
        sizeof(granny_smith.a) 
        + sizeof(granny_smith.weight) 
        + sizeof(granny_smith.protein_per_gram); 
    return 0; 
} 
+0

* "как' uint8_t * '. (Нужно печатать байты)" * Может нарушать правило строгого сглаживания. Существуют исключения для типов 'char'. – dyp

+2

'sizeof (Apple :: a)' является действительным C++ (начиная с C++ 11), нет необходимости в объекте. – dyp

+0

@ dyp Действительный * C++ 11 * вы имеете в виду. – Constructor

0

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

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

Ваши функции будут принимать в качестве аргументов void * и size_t для адреса и sizeof структуры.

0) Позвольте пользователю создать структуру требуемого типа.

1) позволяет пользователю вызова функции из ваших, которая устанавливает все байты 0.

2) позволяет пользователю присвоить значение каждого поля структуры.

3) позволяет пользователю вызвать функцию твоих, которая хранит запись каждого байта, который по-прежнему 0.

4) позволяет пользователю вызвать функцию твоих, которая устанавливает все байты 1.

5) позвольте пользователю снова назначить значение для каждого поля структуры. (То же самое значение, что и в первый раз!)

6) Позвольте пользователю вызвать функцию и подсчитать оставшиеся байты 1 и были отмечены ранее. Это байты заполнения.

Повод попробовать со значениями 0, то 1 состоит в том, что значения, назначенные пользователем, могут включать байты 0; но они не могут быть байтами 0 и байтами 1 одновременно, поэтому один из тестов исключит их.

struct _S { int I; char C } S; 

Fill0(S, sizeof(S)); 

// User cooperation 
S.I= 0; 
S.C= '\0'; 

Mark0(S, sizeof(S)); // Has some form of static storage 

Fill1(S, sizeof(S)); 

// User cooperation 
S.I= 0; 
S.C= '\0'; 

DetectPadding(S, sizeof(S)); 

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

void Assign(void* pS) // User-written callback 
{ 
    struct _S& S= *(struct _S)pS; 

    S.I= 0; 
    S.C= '\0'; 
} 
1

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

Это означает либо шаблоны (которые отклоняют ваш профессор), void *, либо переменное количество аргументов (аналогично printf).

Функция должна напечатать байты структуры

void your_function(void* data, std::size_t size) 
{ 
    std::uint8_t* bytes = reinterpret_cast<std::uint8_t*>(data); 

    for(auto x = bytes; x != bytes + size; ++x) 
     std::clog << "0x" << std::hex << static_cast<std::uint32_t>(*x) << " "; 
} 

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

В этом случае я потерян: байты, используемые для заполнения, являются (по определению) не частью структуры. Рассмотрим:

struct x { char c; char d; char e; }; // sizeof(x) == 3; 

x instance{ 0, 0, 0 }; 
your_function(&instance, sizeof(x)); // passes 3, not 4 (4 for 32bits architecture) 

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

Есть несколько возможностей здесь:

  1. Ваших проф.узнал «храбрый» C++, который считался хорошим кодом 10 или 20 лет назад и не обновлял его знания (здесь есть код C-стиля, указатели, прямой доступ к памяти и «умные хаки»).

  2. Он не знал, как точно выразить то, что он хотел, или использовать терминологию («написать функцию для любого типа данных» слишком расплывчато: как разработчик, если я получил это задание, первое, что нужно сделать do будет спрашивать подробности - как «как это будет использоваться?» и «что такое ожидаемая подпись функции»).

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

  3. Он имел в виду, что вы должны написать произвольный тип данных (например, мой struct x) и определить свой API вокруг этого (маловероятный).

+2

* «байты, используемые для заполнения, (по определению) не являются частью структуры» * Я не уверен что вы имеете в виду здесь. 'sizeof' и' alignof' должны быть совместимы с арифметикой указателей (внутри массива), поэтому любое дополнение отображается в структуре 'sizeof'. – dyp

+0

Байт для заполнения - часть структуры. Просто в вашем примере заполнение не требуется (в большинстве архитектур). Попробуйте с struct test {char i; int j; }; который выводит 8 для меня. – Veritas

Смежные вопросы