Calling C++ (member) functions dynamically - c++

Suppose I have some reflection metadata, which has the following information:
enum class type { t_int, t_double, t_str /* etc... */ };
struct meta_data
{
void* function;
void* instance;
std::vector<type> param_types;
};
std::map<std::string, meta_data> ftable;
I would like to call functions in this map, given the function names and the parameters both as strings. My problem is not converting the parameters (e.g. with boost::lexical_cast), but casting to the right type of function pointer and invoking the function. If I allow possible 8 types and maximum 8 parameters, that's already a lot of branches in my code. What I want to avoid (pseudo code):
switch (md.param_types.size())
{
case 0:
cast function pointer, call it
break;
case 1:
switch (md.param_types[0])
{
case t_int:
int param = boost::lexical_cast(param_strings[0]);
cast function pointer, call with param
case ...
}
break;
case 2:
switch (md.param_types[0]) {
case t_int:
int param = boost::lexical_cast(param_strings[0]);
switch (md.param_types[1]) {...} // second param type..
}
break;
case n...
}
That blows up very quickly with the number of parameters and possible types. I'm looking for some solution along the lines of (pseudo code):
for (auto& p : paramter_strings)
{
convert p to a variable of matching type (type id comes from meta_data).
store value
}
call function with stored values
i.e. no branching for the function invocation. How can I do this with the least amount of boilerplate code (with possibly supporting arbitrary number of parameters)? You can think of this as creating bindings to a custom script language.

I came up with one approach.
Suppose you have a vector of unsigned int V and you know that
every element of the vector is a nonnegative number
which is less than N (or, say, 20).
Here is what you would call to change the vector V to a
positive integer:
n = sequence_to_code(V,N); // or n = encode(V,20U);
Here is the code.
long sequence_to_long(const std::vector<unsigned int> & L,
unsigned long n) {
long result = 0L;
std::vector<unsigned int>::const_iterator w=L.begin(),e=L.end();
if(w!=e) {
result += (*w)+1;
unsigned long the_pow = n;
unsigned int i = 1U;
++w;
while(w!=e) {
result += (*w+1)*(the_pow);
++w;++i;the_pow *= n;
}
}
return result;
}
Actually, I probably should have returned "unsigned long".
In addition, you can use this same routine with a program which creates
a text file. This text file would contain C++ code. Suppose you created
"the_defines.hpp". I will illustrate by example...
For example, say we have t_int=0; t_double = 1, d_str = 2
and there are only three types.
Then "the_define.hpp" could be the file:
#define TYPE_EMPTY 0U
#define TYPE_INT 1U
#define TYPE_DOUBLE 2U
#define TYPE_STR 3U
#define TYPE_INT_INT 4U
#define TYPE_DOUBLE_INT 5U
then this code could be used in the following
way:
std::vector<unsigned int> L;
// add entries to L
long n = sequence_to_long(L,3UL);
switch(n) {
case TYPE_INT:
std::cout << "an integer\n";
break;
case TYPE_INT_DOUBLE:
std::cout << "two args; first is an int; second is a double\n:
break;
}
Of course, you could create a text file which has the code for a very
long enum (if you care to avoid #define). For example,
enum class extended_type {
type_int,
type_double,
type_str,
type_int_int,
type double_int,
and so on.
You could also write a program which creates (one or more) text files.
These text files would also by C++ code. For example, your created file
could be:
swtich(n) {
case empty:
FILLIN
break;
case t_int:
FILLIN
break;
and so on until
case t_str_str:
FILLIN;
break;
}
I would also recommend casting using an inline function or a regular
function. For example,
inline int inside_int(foo f) {
const bar & b = * reinterpret_cast<const bar *>(f.pointer());
return b.d_x;
}
I recommend this due to DRY (don't repeat yourself) and being
able to search for all instances of the function.
I know that these program does not handle errors (overflow,
zero pointers, etc.)
Mark

Related

Is there a way to instantiate all the c++ template sizes at compile time?

The c++/cli template below is working, but it seems like there ought to be a way to generalize the template further or add a helper that can create the template instances at compile time.
Was thinking something like http://en.cppreference.com/w/cpp/utility/integer_sequence might work, but need some assistance with the helper / implementer function.
Simplified main to demonstrate the desired syntax vs what is currently used:
int main(array<String^>^ args) {
// the actual number of possible char lengths is sparse (generally)
// but the API allows for 1-1024
List<int>^ varList = gcnew List<int>();
varList->Add(40);
varList->Add(80);
varList->Add(128);
SortedList<int, List<String^>^>^ allStrings = gcnew SortedList<int, List<String^>^>();
// want something like this, but the compiler complains that
// the template is invalid expectes compile-time constant expressions
for each(int key in varList) {
allStrings->Add(key, UpdateTest<key>());
}
// this works, but has 1024 lines of case N:
for each(int key in varList) {
switch (key) {
case 1: allStrings->Add(key, UpdateTest<1>());
case 2: allStrings->Add(key, UpdateTest<2>());
case 3: allStrings->Add(key, UpdateTest<3>());
//... all 1024 possible char[N] sizes...
case 1024: allStrings->Add(key, UpdateTest<1024>());
}
}
}
Template works with the 1024 switch case N: calls. Is there a way to have a helper / implementer instantiate all 1024 without the cases?
template <std::size_t N> List<String^>^ APIwrapper::UpdateTest() {
typedef char CHARX[N]; // N valid for 1 to 1024
CHARX vals[MAXFIELDS];
// NATIVE C++ VendorAPI(short, void*) vals is the address of the word aligned destination data
int count = VendorAPI(N, &vals);
List<String^>^ retList = gcnew List<String^>();
for (int c = 0; c < count; c++) {
CHARX temp;
strncpy(temp, vals[c], N); // \0 terminated char arrays
String^ x = gcnew String(temp);
retList->Add(x->Substring(0, N)->Trim());
}
return retList;
}
Following answer works for c++14, I don't know if it's compatible with cli.
You can use templates to generate a std::array of function pointers:
using UpdateTestPtr = decltype(&UpdateTest<0>);
// Struct used to generate the array's content.
template<typename Sequence>
struct UpdateTestArrayImpl;
// Specialization used to get the values in the integer sequence.
template<std::size_t... indices>
struct UpdateTestArrayImpl<std::integer_sequence<std::size_t,indices...>> {
static constexpr std::array<UpdateTestPtr,sizeof...(indices)> value{UpdateTest<indices>...};
};
// Factorise sequence creation
template<std::size_t N>
using UpdateTestArray = UpdateTestArrayImpl<std::make_index_sequence<N>>;
static constexpr std::size_t N = 512;
// The array is needed at runtime. Create a normal (not constexpr) instance.
static std::array<UpdateTestPtr,N> functionArray = UpdateTestArray<N>::value;
And turn the switch/case into an array lookup:
for each(int key in varList) {
allStrings->Add(key, functionArray[key]());
}
Live demo
Some compilers might produce a "template instantiation depth" error, depending on how make_integer_sequence is implemented. The max limit of recursion depth can normally be increased with compiler options.
Don't do this with templates.
You're using templates to turn a single large block of memory (CHARX vals[MAXFIELDS];) into lots of individual strings. Instead, do that yourself.
List<String^>^ APIwrapper::UpdateTest(size_t size)
{
char* vals = new char[size * MAXFIELDS];
// NATIVE C++ VendorAPI(short, void*) vals is the address of the word aligned destination data
int count = VendorAPI(size, vals);
List<String^>^ retList = gcnew List<String^>();
char temp[1025]; // max size + 1.
for (int c = 0; c < count; c++)
{
// Instead of relying on the compiler to know that [1] should be 10 bytes in,
// [2] should be 20 bytes in, etc, do that yourself.
strncpy(temp, &vals[size * c], size);
temp[size] = '\0'; // safety
String^ x = gcnew String(temp);
retList->Add(x->Trim());
}
delete [] vals;
return retList;
}
Now, having said that: This is an unusual API. Effectively, you're passing a block of memory, and a stride for the placement of each string. That's somewhat strange, but also only some data can be retrieved with each stride value??? That's very strange. I would check if the vendor's API will still respond properly if 1024 is always used as the stride.

C++ and dynamically typed languages

Today I talked to a friend about the differences between statically and dynamically typed languages (more info about the difference between static and dynamic typed languages in this SO question). After that, I was wondering what kind of trick can be used in C++ to emulate such dynamic behavior.
In C++, as in other statically typed languages, the variable type is specified at compile time. For example, let's say I have to read from a file a big amount of numbers, which are in the majority of the cases quite small, small enough to fit in an unsigned short type. Here comes the tricky thing, a small amount of these values are much bigger, bigger enough to need an unsigned long long to be stored.
Since I assume I'm going to do calculations with all of them I want all of them stored in the same container in consecutive positions of memory in the same order than I read them from the input file.. The naive approach would be to store them in a vector of type unsigned long long, but this means having typically up to 4 times extra space of what is actually needed (unsigned short 2 bytes, unsigned long long 8 bytes).
In dynamically typed languages, the type of a variable is interpreted at runtime and coerced to a type where it fits. How can I achieve something similar in C++?
My first idea is to do that by pointers, depending on its size I will store the number with the appropriate type. This has the obvious drawback of having to also store the pointer, but since I assume I'm going to store them in the heap anyway, I don't think it matters.
I'm totally sure that many of you can give me way better solutions than this ...
#include <iostream>
#include <vector>
#include <limits>
#include <sstream>
#include <fstream>
int main() {
std::ifstream f ("input_file");
if (f.is_open()) {
std::vector<void*> v;
unsigned long long int num;
while(f >> num) {
if (num > std::numeric_limits<unsigned short>::max()) {
v.push_back(new unsigned long long int(num));
}
else {
v.push_back(new unsigned short(num));
}
}
for (auto i: v) {
delete i;
}
f.close();
}
}
Edit 1:
The question is not about saving memory, I know in dynamically typed languages the necessary space to store the numbers in the example is going to be way more than in C++, but the question is not about that, it's about emulating a dynamically typed language with some c++ mechanism.
Options include...
Discriminated union
The code specifies a set of distinct, supported types T0, T1, T2, T3..., and - conceptually - creates a management type to
struct X
{
enum { F0, F1, F2, F3... } type_;
union { T0 t0_; T1 t1_; T2 t2_; T3 t3_; ... };
};
Because there are limitations on the types that can be placed into unions, and if they're bypassed using placement-new care needs to be taken to ensure adequate alignment and correct destructor invocation, a generalised implementation becomes more complicated, and it's normally better to use boost::variant<>. Note that the type_ field requires some space, the union will be at least as large as the largest of sizeof t0_, sizeof t1_..., and padding may be required.
std::type_info
It's also possible to have a templated constructor and assignment operator that call typeid and record the std::type_info, allowing future operations like "recover-the-value-if-it's-of-a-specific-type". The easiest way to pick up this behaviour is to use boost::any.
Run-time polymorphism
You can create a base type with virtual destructor and whatever functions you need (e.g. virtual void output(std::ostream&)), then derive a class for each of short and long long. Store pointers to the base class.
Custom solutions
In your particular scenario, you've only got a few large numbers: you could do something like reserve one of the short values to be a sentinel indicating that the actual value at this position can be recreated by bitwise shifting and ORing of the following 4 values. For example...
10 299 32767 0 0 192 3929 38
...could encode:
10
299
// 32767 is a sentinel indicating next 4 values encode long long
(0 << 48) + (0 << 32) + (192 << 16) + 3929
38
The concept here is similar to UTF-8 encoding for international character sets. This will be very space efficient, but it suits forward iteration, not random access indexing a la [123].
You could create a class for storing dynamic values:
enum class dyn_type {
none_type,
integer_type,
fp_type,
string_type,
boolean_type,
array_type,
// ...
};
class dyn {
dyn_type type_ = dyn_type::none_type;
// Unrestricted union:
union {
std::int64_t integer_value_;
double fp_value_;
std::string string_value_;
bool boolean_value_;
std::vector<dyn> array_value_;
};
public:
// Constructors
dyn()
{
type_ = dyn_type::none_type;
}
dyn(std::nullptr_t) : dyn() {}
dyn(bool value)
{
type_ = dyn_type::boolean_type;
boolean_value_ = value;
}
dyn(std::int32_t value)
{
type_ = dyn_type::integer_type;
integer_value_ = value;
}
dyn(std::int64_t value)
{
type_ = dyn_type::integer_type;
integer_value_ = value;
}
dyn(double value)
{
type_ = dyn_type::fp_type;
fp_value_ = value;
}
dyn(const char* value)
{
type_ = dyn_type::string_type;
new (&string_value_) std::string(value);
}
dyn(std::string const& value)
{
type_ = dyn_type::string_type;
new (&string_value_) std::string(value);
}
dyn(std::string&& value)
{
type_ = dyn_type::string_type;
new (&string_value_) std::string(std::move(value));
}
// ....
// Clear
void clear()
{
switch(type_) {
case dyn_type::string_type:
string_value_.std::string::~string();
break;
//...
}
type_ = dyn_type::none_type;
}
~dyn()
{
this->clear();
}
// Copy:
dyn(dyn const&);
dyn& operator=(dyn const&);
// Move:
dyn(dyn&&);
dyn& operator=(dyn&&);
// Assign:
dyn& operator=(std::nullptr_t);
dyn& operator=(std::int64_t);
dyn& operator=(double);
dyn& operator=(bool);
// Operators:
dyn operator+(dyn const&) const;
dyn& operator+=(dyn const&);
// ...
// Query
dyn_type type() const { return type_; }
std::string& string_value()
{
assert(type_ == dyn_type::string_type);
return string_value_;
}
// ....
// Conversion
explicit operator bool() const
{
switch(type_) {
case dyn_type::none_type:
return true;
case dyn_type::integer_type:
return integer_value_ != 0;
case dyn_type::fp_type:
return fp_value_ != 0.0;
case dyn_type::boolean_type:
return boolean_value_;
// ...
}
}
// ...
};
Used with:
std::vector<dyn> xs;
xs.push_back(3);
xs.push_back(2.0);
xs.push_back("foo");
xs.push_back(false);
An easy way to get dynamic language behavior in C++ is to use a dynamic language engine, e.g. for Javascript.
Or, for example, the Boost library provides an interface to Python.
Possibly that will deal with a collection of numbers in a more efficient way than you could do yourself, but still it's extremely inefficient compared to just using an appropriate single common type in C++.
The normal way of dynamic typing in C++ is a boost::variant or a boost::any.
But in many cases you don't want to do that. C++ is a great statically typed language and it's just not your best use case to try to force it to be dynamically typed (especially not to save memory use). Use an actual dynamically typed language instead as it is very likely better optimized (and easier to read) for that use case.

Access elements in Struct by Address

I've done some research and I cant quite find what I'm looking for on here or google. Is there a way to access the elements in a Customer by address (and not by using customer[i].bottles). I cannot modify the struct so I cannot put the properties into an array.
typedef struct Customer {
int id;
int bottles;
int diapers;
int rattles;
} Customer;
Customer customers[100];
void setValue(int custInd, int propertyInd) {
//propertyInd would be 1 for id, 2 for bottles
//Attempting to set customers[0].bottles
*(&customers[custInd]+propertyInd) = 5;
}
I thought I'd be able to do this but I got various errors. Knowing that the "bottles" value will be the second space in memory from the address of a Customer shouldn't i be able to directly set the spot.
I know this may be improper code but I would like to understand how and why does/doesnt work. I also promise I have reasons for attempting to do this over the conventional way hah
Instead of using propertyInd, perhaps pass an offset into the structure. That way, the code will work even if the layout changes dramatically (for example, if it includes non-int fields at the beginning).
Here's how you might do it:
void setValue(int custInd, int fieldOffset) {
int *ptr = (int *)((char *)&customers[custInd] + fieldOffset);
*ptr = 5;
}
...
setValue(custInd, offsetof(Customer, bottles));
offsetof is a standardized macro that returns the offset, in bytes, from the start of the structure to the given element.
If you still want to use indices, you can compute the offset as propertyInd * sizeof(int), assuming every field in the struct is an int.
You can't do this:
*(&customers[custInd]+propertyInd) = 5;
because the type of &customers[custInd] is struct Customer*, not int *. So &customers[custInd]+propertyInd means the same thing as &customers + custInd + propertyInd or, in other words, &customers[custInd + propertyInd]. The assignment then attempts to set a structure value to the integer 5, which is obviously illegal.
What I suppose you meant was
((int*)&customers[custInd])[propertyInd] = 5;
which would compile fine, and would probably work[*], but is undefined behaviour because you cannot assume that just because a struct consists of four ints, that it is laid-out in memory the same way as int[4] would be. It may seem reasonable and even logical that they layout be the same, but the standard doesn't require it, so that's that. Sorry.
As #iharob suggests in a comment, you might find a compiler clever enough to generate efficient code from the following verbiage:
void setValue(int custInd, int propertyInd, int value) {
//propertyInd would be 1 for id, 2 for bottles
switch (propertyInd) {
case 1: customers[custInd].id = value; break;
case 2: customers[custInd].bottles = value; break;
case 3: customers[custInd].diapers = value; break;
case 4: customers[custInd].rattles = value; break;
default: assert(0);
}
}
*: Actually, it would (probably) work if propertyInd for id were 0, not 1. C array indices start at 0.
&customers[custInd] is a pointer to customers[custInd], so &customers[custInd]+propertyInd is a pointer to customers[custInd+propertyInd]. It is not a pointer to a member. It will have type pointer to Customer. The value of that pointer will be equal to &(customers[custInd+propertyInd].id), but is not a pointer to int - hence the compiler error.
Your bigger problem is that four int in a struct are not necessarily laid out like an array of int - there may be padding between struct members. So, if we do
int *p = &(customers[custInd].id);
then p+1 is not necessarily equal to &(customers[custInd].bottles).
So you will need to do something like
void setValue(int custInd, int Offset)
{
int *ptr = (int *)(((char *)&customers[custInd]) + Offset);
*ptr = 5;
}
/* and to call it to set customers[custInd].bottles to 5 */
setValue(custInd, offsetof(Customer, bottles));

C++ integer type: special meaning for certain values

We are warned against magic numbers in code with good reason, but is there a good, expressive and type-safe way to solidify constants which have special meaning? I can think of two possible ways:
Method 1:
typedef int NumberOfThreads;
const NumberOfThreads automaticNumberOfThreads = 0;
Method 2:
class NumberOfThreads
{
NumberOfThreads(int n) : value(n) {}
static NumberOfThreads automatic() { return NumberOfThreads(0); }
bool isAutomatic() const { return value == automatic(); }
int value;
};
I don't really want a complex type, but I do want my special value to be closely tied to the type. In method 1 it isn't, and lazy users might just hardcode assignment or comparison to 0.
Method 2 seems a bit heavy for something that isn't much more than an integer value.
Question could be extended to non-integer types and multiple special values.
Perhaps something is possible with enum?
Edit:
I realized I can hide the value from the user by using extern in my header file
I don't agree with what you do in method 1. There is no need for NumberOfThreads type. That is a constant actually, "number of threads" and the number is an integer. So this is enough and more readable in my opinion.
const int NumberOfThreads = 0;
Enum is basically just giving numbers names. So that should work fine.
This sample usage shows correct usage enforced and magic value hidden in a the implementation of a function.
int numberOfThreads;
/* ... */
numberOfThreads = automaticNumberOfThreads();
/* ... */
numberOfThreads = 1;
/* ... */
numberOfThreads = 16;
/* ... */
if (numberOfThreads == automaticNumberOfThreads())
{
/* ... */

Declaring a data type dynamically in C++

I want to be able to do the following:
I have an array of strings that contain data types:
string DataTypeValues[20] = {"char", "unsigned char", "short", "int"};
Then later, I would like to create a variable of one of the data types at runtime. I won't know at compile time what the correct data type should be.
So for example, if at runtime I determined a variable x needed to be of type int:
DataTypeValues[3] x = 100;
Obviously this won't work, so how could I do something like this?
The simple answer is that you can't - types need to be known at compile time in C++. You can do something like it using things like boost::any or unions, but it won't be pretty.
you would have to use unions to achieve something like that, but handling unions is a very difficile matter, so you should choose a container class which wraps the union logic behind an interface like Boost.Variant or Qts QVariant
You can't. This kind of run-time metaprogramming is not supported in C++.
Everyone saying you can't do this in C++ is missing one obvious solution. This is where you could use a base class, you need to define the commonly used interface there, and then all the derived classes are whatever types you need. Put it in a smart pointer appropriate for a container and there you go. You may have to use dynamic type inference if you can't put enough of the interface in the base class, which is always frowned upon because it's ugly, but it's there for a reason. And dynamically allocating your types probably isn't the most efficient thing, but as always, it depends on what you're using it for.
I think you are really looking for a dynamically-typed language. Embed an interpreter if you must stick with C++!
Or you could implement something akin to the component model using interfaces to work with wrapped data. Start with the cosmic base class - IObject, then implement interfaces for IInteger, IDouble, IString, etc. The objects themselves would then get created by a factory.
Or you could just use void buffers with a factory... That's the age-old way of avoiding static typing in C/C++ (without the use of inheritance-based polymorphism). Then sprinkle in generous amounts of reinterpret_cast.
The closest you can get is with templates:
template<int i> class Data { };
template<> class Data<0> { typedef char type; }
template<> class Data<1> { typedef unsigned char type; }
template<> class Data<2 { typedef short type; }
template<> class Data<3> { typedef int type; }
Data<3>::Type x;
If you need something a lot more complex, Boost has a C++-Python bridge.
use union and make your own dynamic class.
the pseudocode like:
union all{
char c;
unsigned char uc;
short s;
int i;
};
class dynamic{
public:
char Type;
all x;
template <class T>
dynamic(T y){
int Int;
char Char;
unsigned char Uchar;
short Short;
if (typeof(y) == typeof(Char)){
Type = 1;
}else if (typeof(y) == typeof(Uchar)) {
Type = 2;
}else if (typeof(y) == typeof(Short)) {
Type = 3;
}else{
Type = 4;
}
switch (Type) {
case 1: x.c = y; break;
case 2: x.uc = y; break;
case 3: x.s = y; break ;
case 4: x.i = y; break ;
}
}
auto get() {
switch(Type) {
case 1: return x.c;
case 2: return x.uc;
case 3: return x.s;
case 4: retuen x.i;
}
}
//also make the operators function you like to use
} ;
however you should avoid using the dynamic type as possible as you can because it is memory inefficient
(in this example, each object of dynamic will takes 5 bytes)
it will also slow down your code (a bit).if in your example you want to use dynamic type of number variable only to reduce memory usage, you should forget about dynamic and just use the integer as the type (where integer can contain all of char, unsigned char, and short at once).
but if you want to use it because you need a dynamic type between something really different (example between an int and a string or a custom object), then it will be one of your option.
The only thing you can do is manually loop through the types and compare each individual one. There's also the potential to use a factory object here - but that would involve the heap.
Visual Basic's 'Variant' data type is what you are talking about. It can hold anything, primary data types, arrays, objects etc.
"The Collection class in OLE Automation can store items of different data types. Since the data type of these items cannot be known at compile time, the methods to add items to and retrieve items from a collection use variants. If in Visual Basic the For Each construct is used, the iterator variable must be of object type, or a variant." -- from http://en.wikipedia.org/wiki/Variant_type
The above page gives some insights on how variants are used and it shows how OLE is used in C++ for dealing with variants.
In your simple example, there would be little benefit in not simply using the widest type in the list as a generic container and casting to the smaller types when necessary (or even relying on implicit casts).
You could get elaborate with unions, classes, polymorphism, RTTI, Boost variants etc, but merely for a list of different width integers it is hardly worth the effort.
It seems to me you have a perceived problem for which you have invented an impractical solution for which you are now asking for help. You'd probably be far better off describing your original problem rather than making your solution the problem!
Also, don't forget that all the functions that must operate on this mysterious data type. Most functions are designed to use only one type, such as addition. The functions are overloaded to handle additional types.
How do you know at run-time what the variable type is?
The only way that come to mind now is the old C style where pointer to void was used like:
void *unkown;
Leter on you can assign any object to it like below:
unkown = (void *)new int(4);
If you know the type in the runtime then you may run specified function on such variable like below:
if(type==0) { // int
printf("%d\n", * ((int*)unkown) );
} else {
// other type
}
This way (casting void*) is used for example when malloc [, etc.] function is used.
I'm not saying it is a good practise when c++ is now much more developed.
Still agree with persons that saying it is not the best solution for your problem. But maybe after some redesign you may find it helpful.
You may find also interesting auto type since C++11.
http://en.cppreference.com/w/cpp/language/auto
I guess this reply would be a few years late. But for people who might happen to view this thread, a possible solution for this would be using variable templates. For example:
template<typename T>
T var;
template<typename T>
T arr[10];
int main() {
int temp;
var<int> = 2;
cout << var<int> << ' '; // this would output 2
var<char> = 'a';
cout << var<int> << ' '; // var<int> value would be a space character
cout << var<char> << ' '; // this would output 'a'
for(int i = 0; i < 10; i++) {
switch(i % 2) {
case 0:
arr<int>[i] = ++temp;
break;
case 1:
arr<char>[i] = 'a' + ++temp;
break;
}
cout << endl;
for(int i = 0; i < 10; i++) {
switch(i % 2) {
case 0:
cout << arr<int>[i] << ' ';
break;
case 1:
cout << arr<char>[i] << ' ';
break;
}
}
return 0;
}
The only problem with this, is that you would need to know the variable type of what is currently within the variable(e.g. storing in an integer array what the variable's "id"(the id you would give it), for a specific type). If you do not know or do not have a condition to know what is inside a specific variable or array location, I do not suggest using this.
I try to post it in here, but I had format error. I decided to put a link.
Any way you can use (long long) to store addresses because size of address is 8 and size of (long long) also is 8 then it can hold an address.
https://www.flatech.com.au/learning-material/programming/c/object-pointers-to-any-type