Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning different data type depending on the data (C++)

Is there anyway to do something like this?

(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;
}

Thanks

like image 546
Joel Avatar asked May 31 '09 00:05

Joel


People also ask

Can a function return different data types?

Example #1 Use of returnA function can not return multiple values, but similar results can be obtained by returning an array.

How do I return a different data type in CPP?

While C++ does not have an official way to return multiple values from a function, one can make use of the std::pair , std::tuple , or a local struct to return multiple values.

What are the data type of variables that can be returned by AC function?

The C language has five types data types: int, float,char,double and void. Variables are declared using these data types, and alphanumeric values are provided. For example, char accepts a single character, int accepts integer value, float accepts a decimal number, and void is used as a return type.

Can you return more than one value in C++?

A C++ function can return only one value. However, you can return multiple values by wrapping them in a class or struct. Or you could use std::tuple , if that is available with your compiler.


3 Answers

If you can use a template argument instead of a normal parameter, you can create a templated function that returns the correct type for each depth value. First there needs to be some definition of the correct type according to depth. You can define a template with specializations for the different bit sizes:

// 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; };

The this definition can be used to declare a templated function that returns the correct type for every bit value:

// 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; }
like image 100
sth Avatar answered Sep 19 '22 14:09

sth


No. The return type of a C++ function can only vary based on explicit template parameters or the types of its arguments. It cannot vary based on the value of its arguments.

However, you can use various techniques to create a type that is the union of several other types. Unfortunately this won't necessarily help you here, as one such technique is void * itself, and getting back to the original type will be a pain.

However, by turning the problem inside out you may get what you want. I imagine you'd want to use the code you posted as something like, for example:

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]);
}

Because C++ needs to know the type of p_pixels at compile time, this won't work as-is. But what we can do is make bitmap_operation itself be a template, then wrap it with a switch based on the depth:

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!");
}

Now the compiler will automatically generate three implementations for bitmap_operation_impl for you.

like image 42
bdonlan Avatar answered Sep 20 '22 14:09

bdonlan


You can allocate some memory on the heap, and return a void* that you cast to the type that was allocated. Its a dangerous and unsafe way of working and is an old C trick.

You could return a union that contains all valid datatypes (and a selection indicator).

You could use templates, which is the recommended C++ way for this kind of thing.

You could provide a set of overloaded functions that take a parameter (of each type) as a reference - the compiler will decide which function to call based on the datatype. I often prefer this way as I think its the simplest.

like image 29
gbjbaanb Avatar answered Sep 17 '22 14:09

gbjbaanb