C++ One std::vector containing template class of multiple types

前端 未结 5 951
太阳男子
太阳男子 2021-01-31 02:03

I need to store multiple types of a template class in a single vector.

Eg, for:

template 
class templateClass{
     bool someFunction()         


        
5条回答
  •  南旧
    南旧 (楼主)
    2021-01-31 02:31

    Solution nr. 1

    This solution inspired by Sean Parent's C++ Seasoning talk. I highly recommend to check it out on youtube. My solution simplified a bit and the key is to store object in method itself.

    One method only

    Create a class that will invoke method of stored object.

    struct object {
        template 
        object(T t)
        : someFunction([t = std::move(t)]() { return t.someFunction(); })
        { }
    
        std::function someFunction;
    };
    

    Then use it like this

    std::vector v;
    
    // Add classes that has 'bool someFunction()' method
    v.emplace_back(someClass());
    v.emplace_back(someOtherClass());
    
    // Test our vector
    for (auto& x : v)
        std::cout << x.someFunction() << std::endl;
    
    
    

    Several methods

    For several methods use shared pointer to share object between methods

    struct object {
        template 
        object(T&& t) {
            auto ptr = std::make_shared>(std::forward(t));
            someFunction = [ptr]() { return ptr->someFunction(); };
            someOtherFunction = [ptr](int x) { ptr->someOtherFunction(x); };
        }
    
        std::function someFunction;
        std::function someOtherFunction;
    };
    

    Other types

    Primitive types (such as int, float, const char*) or classes (std::string etc.) may be wrapped in the same way as object class do but behave differently. For example:

    struct otherType {
        template 
        otherType(T t)
        : someFunction([t = std::move(t)]() {
                // Return something different
                return true;
            })
        { }
    
        std::function someFunction;
    };
    

    So now it is possible to add types that does not have someFunction method.

    v.emplace_back(otherType(17));      // Adding an int
    v.emplace_back(otherType("test"));  // A string
    

    Solution nr. 2

    After some thoughts what we basically done in first solution is created array of callable functions. So why not just do the following instead.

    // Example class with method we want to put in array
    struct myclass {
        void draw() const {
            std::cout << "myclass" << std::endl;
        }
    };
    
    // All other type's behaviour
    template 
    void draw(const T& x) {
        std::cout << typeid(T).name() << ": " << x << std::endl;
    }
    
    int main()
    {
        myclass x;
        int y = 17;
    
        std::vector> v;
    
        v.emplace_back(std::bind(&myclass::draw, &x));
        v.emplace_back(std::bind(draw, y));
    
        for (auto& fn : v)
            fn();
    }
    

    Conclusion

    Solution nr. 1 is definitely an interesting method that does not require inheritance nor virtual functions. And can be used to other stuff where you need to store a template argument to be used later.

    Solution nr. 2, on the other hand, is simpler, more flexible and probably a better choice here.

    提交回复
    热议问题