Wildcarding vector templates - c++

I have to create vector of a special type depending on a user input.
e.g. the user has to choose if he wants to create a vector of ints or a vector of strings.
Is it possible to predefine a vector and define it clearly in a e.g. switch-case?
something like:
vector<WILDCARD> vec;
switch(input) {
case 1:
vec = vector<int>()...
break;
case 2:
vec = vector<string>()....
break;
....

Is it possible to predefine a vector and define it clearly in a e.g. switch-case?
No. C++ is a statically-typed language. That means, type of every variable must be known at compile time, and once its known, it cannot be changed later on - not even at compile-time. So what you're doing is not possible.
If you want to give users to choose the type. Then you can defined variables of all possible choices in each case, and works with the one which user chooses, something like this:
switch(input) {
case 1:
{
std::vector<int> vec;
//work with vec which is vector of int!
}
break;
case 2:
{
std::vector<std::string> vec;
//work with vec which is vector of string!
}
break;
//....
Or if you fear code duplication then you can do this instead:
template<typename T>
void Work()
{
std::vector<T> vec;
//work with vec of type T
}
switch(input) {
case 1:
Work<int>();
break;
case 2:
Work<std::string>();
break;
//....

No you cannot.
Create the vector in the switch case depending on switch case type.
switch(input) {
case 1:
vector<int> vec1;
vec1 = ...
break;
case 2:
vector<String> vec2;
vec2 = ....
break;
....

Since c++ is statically typed you can't do this.
But I guess boost::any or boost::variant will get you close where you want to go.

C++ is a statically typed language, so vec would have to have a predetermined type.
What you probably want to do is wrap what you're using as vec in an object, perhaps an abstract base class that doesn't mention what the vector base type is, and two child classes, one for int and one for string. Then you'd use virtual functions to encapsulate the differences between the vector<int> version and the vector<string> version.

Related

Heterogeneous array implementation

I would appreciate your help!
Which data structure is used to implement heterogeneous array in C or C++ ? The array may contain any standard data types like int,float, char, string etc...
As ravi mentions, the appropriate data structure is called a tag-union (also called variant record). One way to implement it is this:
typedef union {
int tag;
struct {
int tag;
int val;
} int_;
struct {
int tag;
double val;
} double_;
} object;
Then you can make an array of these.
object arr[5];
You use the tag field to indicate which union member is in use. Typically with an enum.
enum type { INT, DOUBLE };
Then set the tag when creating the object, and check the tag before accessing. This can be encapsulated by using constructor functions.
object new_int(int i){
object ret;
ret.tag = INT;
ret.int_.val = i;
return ret;
}
object new_double(double d){
object ret;
ret.tag = DOUBLE;
ret.double_.val = d;
return ret;
}
And you usually want to use a switch on the tag for accessing, writing a different case for each type.
void print_object(object x){
switch(x.tag){
case INT: printf("%d\n", x.int_.val); break;
case DOUBLE: printf("%f\n", x.double_.val); break;
}
}
Or in some circumstances, you may want to fold the array into a single type so it can be accessed without checking the tag each time.
for (i = 0; i < sizeof arr/sizeof*arr; i++)
if (arr[i].tag == INT)
arr[i] = new_double(arr[i].int_.val);
There is no such array in c++ which can store elements of different types nor there is container in stl. Although there's one way to store different element in a container but condition is those types should be related through inheritance.
In C there's a concept called tagged union which can store different types giving tag as a means to specify which variable is actually there.
One more way to do this is using an array of void* pointers. Although that would be quite ugly C++. This would not be truly heterogeneous as you are using a type of pointer that any pointer can be cast into. It is similar to making a collection of base class type and then storing objects of derived classes.
This I got from Stroustrup article:-
If you need a heterogeneous container in C++, define a common interface for all the elements and make a container of those. For example:
class Io_obj { /* ... */ }; // the interface needed to take part in object I/O
vector<Io_obj*> vio; // if you want to manage the pointers directly
vector< Handle<Io_obj> > v2; // if you want a "smart pointer" to handle the objects
Apart from that Boost::Any can also be used:-
vector<Any> v;
I guess you could keep an array of pointers to anything
void* stuff[size];
const char* str = "hello";
int x = 20;
int *array = malloc(sizeof(int) * 5);
stuff[0] = str;
stuff[1] = &x;
stuff[2] = array;
Alternatively, an array of unions if you knew all the types before hand.

defining an unusual 2-D array in C++

I want to reference the 1st Dimension of a 2 Dimensional array using an enum. However, the configurations that each enum value represents sometimes overlap (not in any patterned way), meaning the data in the array will sometimes be the same. I therefore would like to have some elements point to the same array of data, as in the diagram below.
Is there any way of doing this at declaration-time in C++?
Yes, you can build an array like that using an array of pointers; you will be able to reference elements in that array as if it were a regular 2D array. Here is an example:
enum MyEnum {
enumFirst = 0
, enumSecond = 1
, enumSecondShared = 2
, enumThird = 3
};
static int enumFirstData[] = {1, 2, 3};
static int enumSecondData[] = {4, 3, 2};
static int enumThirdData[] = {9, 7, 8};
int *enumData[] = {
enumFirstData
, enumSecondData
, enumSecondData // <== Shared
, enumSecondData
};
Now you can reference elements of this array like this:
for (int i = 0 ; i != 3 ; i++) {
cout << enumData[enumSecondShared][i] << endl;
}
Since you are using C++, using std::vector or std::array is a preferred way of making collections. You can use the same trick as above to establish shared collection elements.
you can define your own container type and use switch/case to map from the enums to the references. that way, you map those enums at declaration time, can use arbitrary enum values, and are more type safe than indexing an array of pointers.
it would look somehow like this (not tested), which specializes the std::map class:
template<class V>
class map<myenum,V>{
V r1,r2,r3;
public:
inline map(){}
inline r1& operator[](myenum e){
switch(e)
{
case E1: return r1;
case E2:
case E3: return r2;
case E4:
case E5: return r3;
}
}
}
map<myenum,vector<int>> example;
(sorry for not writing high-quality std-template style definitions, i'm not that used to program in c++ anymore.)
All you need is just std::map<your_enum_t, data_t*>
You should feel mapping according to your needs

How to make the C++ precompiler do a "loop"

I want to simplify the following code:
switch (index)
{
case 1:
output = function1();
break;
case 2:
output = function2();
break;
case 3:
output = function3();
break;
....
Where index is a compile time constant.
If I would use a precompiler macro, I would need to use it n times, where n is the number of cases. How can I reduce the above mentioned code to O(1) lines of code?
Try this (assuming function 1-n are the real names. and that index is, as you say, a compile time constant):
#define CALLFUNCTION(x) function##x()
output = CALLFUNCTION(1);
correction: this will not work for variables, will work if the constant is used directly. This might defeat the purpose if the provided code is all there is in each case statement.
There is no need to do a switch at all. Alternatively you could use template specialization.
template<int index> function();
output = function<index>();
and specialize the function template for each index.
template<> function<1>(){return 1;} // or {return function1();}
If it is not a compile time constant, you need to generate the switch like Fomin Arseniy suggests. Another option would be to use a array of function pointers
You cannot do it with a macro - but this will work (I think):
int (*functions[])() = { &function1, &function2, &function3};
int output = functions[index]();
May be supermacro can slightly simplify your work.
Simply create "counter.def" file with code:
COUNTER(1)
COUNTER(2)
COUNTER(3)
#undef COUNTER
Then in any case of using switch or any other construction with repeating counting
switch(index)
{
#define COUNTER(i) case i: output = function##i(); break;
#include "counter.def"
}
Late to the party, since then it's useful to check boost libraries on it:
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#define DECL(z, n, _) case n: (function ## n)(); break;
BOOST_PP_REPEAT_FROM_TO(1, 3, DECL, _)
However, if you're in a somewhat newer C++, it's recommended to use template metaprogramming and if constexpr () instead.

C++ check if element is std::vector

i would like to iterate through a vector and check if elements are vectors or strings. Also i need a way to pass different vecors to a function.
Something like this:
using namespace std;
string toCustomString(<some vector> vec) {
string ret = "";
for(size_t i = 0; i < vec.length(); ++i)
if (vec[i] == %vector%)
ret += toCustomString(vec[i]);
else //if type of vec[i] is string
ret += "foo"+vec[i]+"bar";
}
return ret;
}
Well, first i need to know how i can check correctly if vec[i] is a std::vector
Then i need to know how to define the paramater for the function to accept any kind of (multidimensional) vector
std::vector can only contain one type - that is the T in std::vector<T>, which can be accessed with the member value_type.
What you probably are looking for is template specialization:
template<typename T>
string toCustomString(std::vector<T> vec) {
// general case
}
template<>
string toCustomString<std::string>(std::vector<std::string> vec) {
// strings
}
(if you want to partially specialize it over all vectors then you'll need to lift it to a struct)
If you really want to store both strings and vectors in the vector then look at Boost.Variant and Boost.Any
Generally, your <some vector> vec would have type either vector<string> or vector<vector<string>>, for example.
In order to declare the variable, you need its type, and its type also specifies exactly what it stores.
Now, you can work around this using Boost.Variant (or roll your own discriminated union), like so:
typedef boost::variant<std::string, std::vector<std::string>> Vec_of_StringOrVec;
but Dirk Holsopple is right that this isn't idiomatic C++, and you may be better off looking for a different approach.
As everyone says, vectors in C++ only hold one type. There's no need or point in checking the type of each element in turn, which is just as well because there's no way to do that. What you do instead is overload the function on the type of the argument. Something like this:
string toCustomString(const string &str) {
return "foo" +str + "bar";
}
template <typename T>
string toCustomString(const std::vector<T> &vec) {
string ret;
for(size_t i = 0; i < vec.size(); ++i)
ret += toCustomString(vec[i]);
return ret;
}
Now, if someone passes a vector<string> into toCustomString then the call toCustomString(vec[i]) will select the toCustomString(const string &str) overload.
If someone passes a vector<int> into toCustomString then the code won't compile, because there is (currently) no toCustomString(int) overload[*].
If someone passes a vector<vector<string>> to toCustomString then toCustomString(vec[i]) will pass a vector<string>, see above.
In all three cases, different toCustomString functions are called. In the first case it's toCustomString<string>(const vector<string>&), which is a different instantiation of the toCustomString template from the third case, toCustomString<vector<string>>(const vector<vector<string>>&). The middle case tries to instantiate toCustomString<int>, but fails because toCustomString(v[i]) doesn't match any function it knows about.
All of this is determined at compile time. The point of templates is to create multiple functions (or classes) with particular differences between them. In this case the difference is the type of vector passed in.
[*] This seems in line with your claim that vec[i] must be either a vector or a string, not any third option. If you wanted for example the return value for a vector<something_else> to be empty, then you could add a catch-all template:
template <typename T>
string toCustomString(const T &) {
return string();
}
and of course you can add more overloads for any other types you want to handle.

Using std::map inside switch case

I have this:
map<string,int> a;
int b;
And i'd like to make this:
switch(b)
{
case a["someStr1"]:
someCode1();
break;
case a["someStr2"]:
someCode2();
break;
etc.
}
But it doesn't compiles. How to implement this correctly?
switch conditions need to be constants, so what you want to do here is not possible.
You're better off using some if statements.
switch/case are meant for constants (e.g., enum, ints etc.).
You can use the map<>::iterator to run through the values and compare with b.
for(map<string,int>::const_iterator it = a.begin(), end = a.end(); it != end; it++)
{
if(it->second == b)
{
...
break;
}
}
This way you can avoid the code duplication for comparison, if your a is large enough.
Also, you can explore the option of replacing for loop with for_each.
You can't.
Expression after case in a switch statement must be integral compile-time constant. So a literal (42), const int variable initialized with a literal (const int x = 66 ... case x:) or enum value. And thats about it.
The reason this is so strict is efficiency. Compilers usually create labels for each case and if you know the value for each label at compile time, you can make some nice optimizations that avoid most of the overhead a normal code branching has.
In your case just go with if-else:
if(b == a["someStr1"]) {
//...
} else if(b == a["someStr2"]) {
//...
} // and so on