Is there a way to store type specifier in variable? I've searched around and found typeid and decltype, but neither of them works as I would like to. decltype doesn't generate variables, and typeid is usually used for typeid().name().
Since typeid().name() outputs the type specifier as const char*, which can be stored and passed around, is there a function to convert const char* back to type specifier? Like:
int a = 1;
auto t = typeid(a).name();
some_function(t) b = 1; //gives int b
I know decltype does exactly this, but it can't "store" the type specifier.
In my recent project I encountered a curious case where the type of a function argument may vary on each call. Normally using function templates would do, but it either requires putting all the code in header which is not allowed in this project, or use explicit intantiation which may get messy since it's hard to list all of the types. Also, Writing multiple function overloads regarding every type is quite messy too.
If there is a way to store the type specifier as variable, then I may use void* to pass the address of the input, and pass the variable containing type specifier into the function, then cast void* back to its original type?
In some way, typeid().names() already offers a way to store and pass a variable's type, I wonder if there's an elegant way to convert it back to type specifier without writing long lists of "strcmp" or other manual conversions.
Thanks!
Edit: More about my project, the function is used as a setter for private class members, the first input is enum regarding the member id, the second is value. The class can also be inherited. The project requires putting as less code as possible in header. OpenCV is used in this project.
In Header.h:
#include "some_other_custom_class.h"
#include <string>
enum BASE_PARA
{
A,
B,
C
}
class Base
{
public:
Base() = default;
virtual ~Base() = default;
//<sometype> may vary regarding the member
virtual void Set(const int& id, const <sometype>& value);
private:
int a;
float b;
map<std::string, double> c;
}
enum DERIVED_A_PARA
{
D,
E
}
class DerivedA : public Base
{
public:
//inherit Set()
virtual void Set(const int& id, const <sometype>& value) override;
private:
map<int, <some_custom_class>> d;
vector<double> e;
}
class DerivedB : public DerivedA //and so on
{
}
In Cpp.cpp:
void Base::Set(const int& id, const <sometype>& value)
{
//processing the input regarding the private member
//<do something here>
switch(id)
{
default:
break;
case A:
a = value;//which means in here <sometype> should be int
break;
case B:
b = value;//<sometype> should be float
break;
case C:
//<sometype> should be map<string, double>
if (<some_code_to_ensure_value_is_not_empty>)
return;
c["first"] = value["first"];
c["second"] = value["first"] + value["second"];
break;
}
}
void DerivedA::Set(const int& id, const <sometype>& value)
{
//something like above
}
I know function template is good for this but can't use it as said above. So I was hoping to change "sometype" into a void* to point to address, and a const char* generated from typeid().name() to mark the actual type. But I can't find a good way to convert const char* back to type specifier.
There are three options
but at some point you'll either have to use templates or write a certain amount of boilerplate/overloads/branches.
The best bet for "[a] type of a function argument [that] may vary" is a function template because that is basically the use case for templates.
If they cannot be in the (possibly) public header files of the project then some kind of internal header might work out. In case the code is only used at a certain point the template can be defined inside a source file (sacrificing reusability).
std::any
in C++17 is some kind of syntactic sugar for type erasure which can give you a more elegant type erasure with std::bad_any_cast exceptions if you cast to a type which isn't held by any
.
void Base::Set(const int& id, std::any const& value)
{
switch(id)
{
case static_cast<int>(BASE_PARA::A):
this->a = std::any_cast<int>(value);
break;
// ... and so on ...
}
}