• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 385
  • Last Modified:

declaring vector type based on size in switch statement

Hi

I would like to declare a vector but its type (whether char, float etc) needs to be determined based on the results of a switch statement.

switch(a){

     case 8:
     {
        std::vector<unsigned char> my_vector; break;
     }
     
    case 16:
    {

        std::vector<unsigned short> my_vector;break;
     }

     case  32:
     {

          std::vector<float> my_vector;break;
      }

    default:
    {
          std::vector<unsigned char> my_vector; break;
     }
}

my_vector.insert(my_vector.begin()+offset,myvalue);

but later down , after the switch statement ends,in the same function , when i try to perform an insert operation on my_vector, i get 'my_vector' :undeclared identifier.

what can i do to ensure that i have a my_vector that is created based on the results of the switch statement?
0
LuckyLucks
Asked:
LuckyLucks
2 Solutions
 
jkrCommented:
You can't do that based on a 'switch' statement, but a template can well serve that purpose. E.g.

template<typename T>
T create_vector_and_add_value(const T myvalue, const size_t offset) {

  std::vector<T> my_vector;

  my_vector.insert(my_vector.begin()+offset,myvalue);

  return my_vector;
} 

Open in new window


Your above code won't work because the vectors you create are 'local' to the scope in between the scope braces ('{}') and therefore no longer valid later in your code. But apart from that, the approach is flawed - how would you return a type that you are not sure of what it is in the beginning?
0
 
HooKooDooKuCommented:
Simply put, variables can not be declared within a switch statement EXCEPT for variables that will have a scope of a single case (and the case must have {} around it:
switch(i)
{
  case 0:
  {
    int j=0;
    //... do stuff with j
  } //j goes out of scope here
}

Open in new window


About the only way I can thing to accomplish what you want to do is to use a pointer or a union.  

If you use a union, then you could use the switch statement to decide which data type within the union to process within the switch statement.

My personal approach would be to define a class and declare a pointer to that class.  Then inside the switch statement, create a new instance of the class where you could pass a parameter to the constructor to determine which 'mode' to create the class.
class myvectors
{
public:
  enum mode
  {
    CharMode,
    ShortMode,
    FloatMode
  ]
  mode m_mode;
  (std::vector<char>)* m_pChar;
  (std::vector<short>)* m_pShort;
  (std::vector<float>)* m_pFloat;
  myvector(mode){
    m_mode = mode;
    m_pChar = NULL;
    m_pShort = NULL;
    m_pFloat = NULL;
    switch( m_mode )
    {
      case CharMode: m_pChar = new std::vector<char>; break;
      case ShortMode: m_pShort = new std::vector<short>; break;
      case FloatMode: m_pFloat = new std::vector<float>; break;
    {;
};

Open in new window

From there, you would directly work with the vector that currently has a value, or when the functionality is the same regardless of the vector used, create a member function that looks at mode and determines which member variable to operate on.

I'm sure there might be some additional options if you started getting into templates.  But again, even there you basically can not change the declaration of a variable within a switch statement.  (In other words, you can change how a variable expresses itself within a switch statement, but you can't change how it is declared)
0
 
chaauCommented:
You can't do this. First of all when you define a variable inside the {...} block it is called that it is declared inside the scope of this block. So, the statement like this:
 {
        std::vector<unsigned char> my_vector; break;
 }

Open in new window

will only exist inside the {...} brackets. That is why you are getting these errors.
The my_vector variable has to be defined in the scope of the code you are going to use, in your case, in the beginning of the program.
To address your problem you have a few options:
1. Define my_vector as a type that is guaranteed to hold all possible values, e.g. double. Then just cast to the type you want inside your switch statement. However, please note that due to double's rounding problems you can experience some unexpected problems when casting the values to/from float.
2. Create a class that will use the type value and a union with different types. Then create the vector using this class. Here is a small example:
class Universal
{
public: 
  union val
  {
    float f;
    unsigned short us;
    unsigned char uc;
  } value;
  int type;
  Universal()
  SetType(int t){type = t;};
  SetFloat(float f)(value.f = f;);
  etc...
};

Open in new window

Now, you can define my_vector as  std::vector<Universal> my_vector;
3. You can define the vector as
 std::vector<void*> my_vector;
and populate the values like this:
 std::vector<void*> my_vector;
switch(a){
    case 16:
    {
        // b is a value you want to insert
        my_vector.push_back(new float(b));break;
     }

Open in new window

Please note that in this case you need to delete every element you are inserting using delete operator:
 while (!my_vector.empty())
  {
    delete my_vector.back();
    my_vector.pop_back();
  }

Open in new window

There are some other options, and I am pretty sure other experts give you their own answers....
0
 
evilrixSenior Software Engineer (Avast)Commented:
Is the value of the variable 'a' known at compile time? If so this is easy to do with a little bit of template trait magic. If not, see above.
0
 
sarabandeCommented:
what can i do to ensure that i have a my_vector that is created based on the results of the switch statement?

if using a void pointer you could do it like that:

enum { chartype, shorttype, floattype };

class VarVector
{
    void * pv;
    int  type;
public:
    VarVector(std::vector<unsigned char>* p) : pv(p), type(chartype) {}
    VarVector(std::vector<unsigned short>* p) : pv(p), type(shorttype) {}
    VarVector(std::vector<float>* p) : pv(p), type(floattype) {}

    void push_back(int off, unsigned char uc) 
    { 
         if (type == chartype) ((std::vector<unsigned char>*)p)->push_back(uc);
    }
};

...
VarVector * pvv = NULL;
switch(a)
{
    case 8:   pvv = new VarVector(new std::vector<unsigned char>()); break;
    case 16: pvv = new VarVector(new std::vector<unsigned short>()); break;
    ...
}

Open in new window


however, the code is not very convenient cause for the insert or push_back function you would need a further switch cause 'myvalue' also needs to be the right type. so the problem is not so much that you need a container that takes an arbitrary type but that you need a variant type. for that the union as shown by jkr is an often used concept, though it is a c-like design and I would not use it for c++.

a c++ variant type would look different:

enum { ebytetype, eu16type, efloattype };

class basevariant
{
public:
      int gettype() = 0;   // makes basevariant an abstract class
};     

class bytevariant : public basevariant
{
      unsigned char uc;
public:
       bytevariant(unsigned char c) : uc(c) {} 
      unsigned char getvalue() { return uc; }
       int gettype() { return ebytetype; }
};
....
class variant
{
     basevariant * pbv;
public:
     variant() : pbv(0) {}
     variant(unsigned char uc) : pbv(new bytevariant(uc)) {}
     // other constructors
     virtual ~variant() { delete pbv; }
};

....
std::vector<variant> vv;
...
switch (a)
{
   case 8: 
   {
         unsigned char uc = (unsigned char)atoi(mystrvalue.c_str());
         vv.insert(vv.begin()+off, uc);
         break;
   }
   ....

Open in new window


the above allows to store different base types to the same vector.

Sara
0

Featured Post

[Webinar] Improve your customer journey

A positive customer journey is important in attracting and retaining business. To improve this experience, you can use Google Maps APIs to increase checkout conversions, boost user engagement, and optimize order fulfillment. Learn how in this webinar presented by Dito.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now