Solved

declaring vector type based on size in switch statement

Posted on 2014-01-12
5
371 Views
Last Modified: 2014-01-29
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
Comment
Question by:LuckyLucks
5 Comments
 
LVL 86

Accepted Solution

by:
jkr earned 250 total points
ID: 39775612
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
 
LVL 16

Expert Comment

by:HooKooDooKu
ID: 39775613
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
 
LVL 25

Expert Comment

by:chaau
ID: 39775622
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
 
LVL 40

Expert Comment

by:evilrix
ID: 39775830
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
 
LVL 34

Assisted Solution

by:sarabande
sarabande earned 250 total points
ID: 39776862
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

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

This article will show you some of the more useful Standard Template Library (STL) algorithms through the use of working examples.  You will learn about how these algorithms fit into the STL architecture, how they work with STL containers, and why t…
This article shows you how to optimize memory allocations in C++ using placement new. Applicable especially to usecases dealing with creation of large number of objects. A brief on problem: Lets take example problem for simplicity: - I have a G…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…

740 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question