Возвращение другого типа данных в зависимости от данных (C ++) - PullRequest
9 голосов
/ 31 мая 2009

Есть ли что-нибудь подобное?

(correct pointer datatype) returnPointer(void* ptr, int depth)
{

    if(depth == 8)
        return (uint8*)ptr;
    else if (depth == 16)
        return (uint16*)ptr;
    else
        return (uint32*)ptr;
}

Спасибо

Ответы [ 5 ]

10 голосов
/ 31 мая 2009

Нет. Тип возвращаемого значения функции C ++ может изменяться только в зависимости от явных параметров шаблона или types ее аргументов. Он не может варьироваться в зависимости от значения своих аргументов.

Однако вы можете использовать различные методы для создания типа, который является объединением нескольких других типов. К сожалению, это не обязательно поможет вам в этом, поскольку одна из таких техник сама по себе void *, и возвращение к первоначальному типу будет проблемой.

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

void bitmap_operation(void *data, int depth, int width, int height) {
  some_magical_type p_pixels = returnPointer(data, depth);
  for (int x = 0; x < width; x++)
    for (int y = 0; y < width; y++)
      p_pixels[y*width+x] = some_operation(p_pixels[y*width+x]);
}

Поскольку C ++ должен знать тип p_pixels во время компиляции, он не будет работать как есть. Но то, что мы можем сделать, это сделать сам bitmap_operation шаблоном, а затем обернуть его переключателем на основе глубины:

template<typename PixelType>
void bitmap_operation_impl(void *data, int width, int height) {
  PixelType *p_pixels = (PixelType *)data;
  for (int x = 0; x < width; x++)
    for (int y = 0; y < width; y++)
      p_pixels[y*width+x] = some_operation(p_pixels[y*width+x]);
}

void bitmap_operation(void *data, int depth, int width, int height) {
  if (depth == 8)
    bitmap_operation_impl<uint8_t>(data, width, height);
  else if (depth == 16)
    bitmap_operation_impl<uint16_t>(data, width, height);
  else if (depth == 32)
    bitmap_operation_impl<uint32_t>(data, width, height);
  else assert(!"Impossible depth!");
}

Теперь компилятор автоматически сгенерирует три реализации для bitmap_operation_impl для вас.

7 голосов
/ 31 мая 2009

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

// template declaration
template<int depth>
struct uint_tmpl;

// specializations for certain types
template<> struct uint_tmpl<8>  { typedef uint8_t type; };
template<> struct uint_tmpl<16> { typedef uint16_t type; };
template<> struct uint_tmpl<32> { typedef uint32_t type; };

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

// generic declaration
template<int depth>
typename uint_tmpl<depth>::type* returnPointer(void* ptr);

// specializations for different depths
template<> uint8_t*  returnPointer<8>(void* ptr)  { return (uint8_t*)ptr;  }
template<> uint16_t* returnPointer<16>(void* ptr) { return (uint16_t*)ptr; }
template<> uint32_t* returnPointer<32>(void* ptr) { return (uint32_t*)ptr; }
1 голос
/ 31 мая 2009

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

Вы можете вернуть объединение, которое содержит все допустимые типы данных (и индикатор выбора).

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

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

0 голосов
/ 31 мая 2009

вы можете сделать это:

, если (глубина == 8) (uint8 *) returnPointer (void * ptr, int deep) {// и т. д.

0 голосов
/ 31 мая 2009

Нет; Вы не можете сделать это в C ++. Правильный ответ - вернуть void *.

Подумайте об этом с противоположной стороны вызова - и с точки зрения компилятора:

Как компилятор сможет проверить, правильно ли используется возвращаемое значение (например, присвоено ли переменной соответствующего типа), если он не может знать, какой из трех возвращаемых типов будет возвращен?

В этот момент понятие присвоения «одного из нескольких типов» возвращаемому значению теряет смысл. Возвращаемый тип функции не имеет в жизни никакой другой цели, кроме как дать возможность компилятору выполнять свою работу; компилятору нужен «один» тип, чтобы иметь возможность выполнять проверку типов. Поскольку вы не знаете, какой из них, до времени выполнения, компилятор не может выполнить проверку типов за вас. Вы должны указать компилятору «прекратить попытки» сопоставить возвращаемое значение с любым конкретным типом указателя - следовательно, вернуть void *.

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

Если значение depth не известно до времени выполнения, то вам, вероятно, следует вернуть void *.

Теперь я предполагаю, что ваша фактическая реализация действительно что-то делает для создания указателя, отличного от того, что показывает ваш пример кода. Ваш пример кода не является реальной функцией; это больше похоже на попытку дублировать то, что делает cast. A cast не является вызовом функции; это директива компилятора, пытающаяся «превратить» его операнд в определенный тип (именно «как», это длинная история для другого поста). Это не операция на языке C ++, а операция компилятора. Вы не можете переписать это в самом C ++.

...