(I've read several existing questions regarding this issue and they seem slightly different and don't make the issue any clearer to me.)
I'm trying to create a vector of key-value pairs in which the value is generic. The code which logically indicates what I need follows:
#include <stdio.h>
#include <string.h>
#include <vector>
template <typename T>
class CCmd
{
protected:
char name[64];
T value;
public:
CCmd(char* _name, T _value)
{
strcpy(name, _name);
value = _value;
}
T getValue()
{
return value;
}
void setValue(T _value)
{
value = _value;
}
};
int main()
{
std::vector<CCmd*> vec;
vec.push_back(new CCmd<int>("gravity", 150));
vec.push_back(new CCmd<char*>("configfile", "config.cfg"));
printf("Value = %d\n", vec[0]->getValue());
printf("Config = %s\n", vec[1]->getValue());
return EXIT_SUCCESS;
}
This fails to compile in every way I think it would be syntactically correct. I read on one question that using a base class to encapsulate the generic class is required, however I tried this by creating an empty class as indicated and made my generic class a subclass of it:
...
class CCmdBase
{
};
class CCmd : public CCmdBase
{
...
and the compiler complains that CCmdBase
doesn't have a member named getValue
which, given that it returns the generic type T, would mean that the base class would also need to be generic for me to define it in there, which means that I'm back where I'm started?
Please help; what am I missing here?
Your approach cannot be easily done in C++. Most probably your design is incorrect and should be improved. It is difficult to advise exact way, but possible solution to have abstract base class with pure virtual functions. Though your virtual function cannot be setValue
or getValue
in your current "design" as function signature must match for virtual functions.
In case you really need to implement approach with different values in the vector look into std::tuple
, boost::variant
and boost::any
. Again do not expect that usage of such solution will be easy to understand and straightforward for you.
This is incorrect: std::vector<CCmd*> vec;
You must specify a type for the template parameter. CCmd
isn't a type, it's the name of a class template. For example , std::vector< CCmd<int> *> vec;
It's not possible to have a vector which directly stores items of different types. The vector must store items of the same type. The thing you are looking for is called a heterogenous container . Standard C++ doesn't have any, but you can simulate one by using a common type which has functions to retrieve the "real" object.
Your idea of std::vector<CCmdBase *>
will work, using runtime polymorphism. Of course you have to actually implement the functions you want in the CCmdBase
class. You can have template functions inside a non-template class definition, eg:
struct CCmdBase
{
template<typename T> T getValue()
{
return dynamic_cast< CCmd<T> & >(*this).getValue();
}
virtual ~CCmdBase() {}
};
As this question was recently tagged as the 'duplicate' of a new question, is should be added that since C++17 we have std::any
The class
std::any
describes a type-safe container for single values of any type.
and std::variant
The class template
std::variant
represents a type-safe union. An instance ofstd::variant
at any given time either holds a value of one of its alternative types, or in the case of error - no value.
as part of the C++ standard.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.