简体   繁体   中英

Vector of template class

(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 of std::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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM