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

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

In C++, if you want a single std::vector to contain elements of multiple types, you typically have to use a common base class or a type-erased container. C++'s type system requires that all elements in a std::vector must be of the same type. Here are some strategies to achieve this:

1. Using a Base Class with Polymorphism

You can define a common base class and derive multiple classes from it. The std::vector can then store pointers or smart pointers to the base class.

Example

#include <iostream> #include <vector> #include <memory> class Base { public: virtual void print() const = 0; // Pure virtual function virtual ~Base() = default; // Virtual destructor }; class Derived1 : public Base { public: void print() const override { std::cout << "Derived1" << std::endl; } }; class Derived2 : public Base { public: void print() const override { std::cout << "Derived2" << std::endl; } }; int main() { std::vector<std::unique_ptr<Base>> vec; vec.push_back(std::make_unique<Derived1>()); vec.push_back(std::make_unique<Derived2>()); for (const auto& item : vec) { item->print(); } return 0; } 

2. Using std::variant

For a fixed set of types, std::variant (introduced in C++17) can be used to store values of different types in a single vector. std::variant provides type-safe access to its values.

Example

#include <iostream> #include <vector> #include <variant> using VariantType = std::variant<int, double, std::string>; int main() { std::vector<VariantType> vec; vec.push_back(1); vec.push_back(3.14); vec.push_back("Hello"); for (const auto& item : vec) { std::visit([](auto&& value) { std::cout << value << std::endl; }, item); } return 0; } 

3. Using Type Erasure with std::any

If you need to store a variety of types without defining a common base class, std::any (introduced in C++17) can be used. std::any allows storing any type and provides type-safe access through std::any_cast.

Example

#include <iostream> #include <vector> #include <any> int main() { std::vector<std::any> vec; vec.push_back(1); vec.push_back(3.14); vec.push_back(std::string("Hello")); for (const auto& item : vec) { if (item.type() == typeid(int)) { std::cout << std::any_cast<int>(item) << std::endl; } else if (item.type() == typeid(double)) { std::cout << std::any_cast<double>(item) << std::endl; } else if (item.type() == typeid(std::string)) { std::cout << std::any_cast<std::string>(item) << std::endl; } } return 0; } 

Summary

  • Polymorphism with Base Class: Use if you have a common interface or base class and need to work with derived types.
  • std::variant: Use for a fixed set of types with type-safe access.
  • std::any: Use for storing any type with runtime type information, but it's less type-safe compared to std::variant.

Choose the method that best fits your use case based on the types you need to handle and the level of type safety you require.

Examples

  1. "How to use a std::vector with a template class for different types in C++?"

    Description: Use a std::vector to store instances of a template class with different types by leveraging polymorphism or type-erasure techniques.

    Code:

    #include <vector> #include <memory> #include <iostream> template <typename T> class MyClass { public: MyClass(T value) : value(value) {} void print() const { std::cout << value << std::endl; } private: T value; }; int main() { std::vector<std::shared_ptr<void>> vec; vec.push_back(std::make_shared<MyClass<int>>(10)); vec.push_back(std::make_shared<MyClass<double>>(3.14)); for (const auto& item : vec) { // You need dynamic_cast and type checks to handle different types safely } return 0; } 

    Explanation: Use std::shared_ptr<void> for type erasure, but you need to handle type checking when accessing elements.

  2. "How to store multiple template class types in a std::vector using a base class?"

    Description: Use a base class and derive your template class from it to store different template instances in a single std::vector.

    Code:

    #include <vector> #include <memory> #include <iostream> class Base { public: virtual ~Base() = default; virtual void print() const = 0; }; template <typename T> class MyClass : public Base { public: MyClass(T value) : value(value) {} void print() const override { std::cout << value << std::endl; } private: T value; }; int main() { std::vector<std::shared_ptr<Base>> vec; vec.push_back(std::make_shared<MyClass<int>>(10)); vec.push_back(std::make_shared<MyClass<double>>(3.14)); for (const auto& item : vec) { item->print(); } return 0; } 

    Explanation: Use a base class with a virtual function to allow polymorphic behavior in the std::vector.

  3. "How to implement type-erasure for different template types in std::vector?"

    Description: Use type-erasure techniques to handle different template types in a std::vector without using base classes.

    Code:

    #include <vector> #include <memory> #include <iostream> #include <typeinfo> class TypeErased { public: virtual ~TypeErased() = default; virtual void print() const = 0; }; template <typename T> class Wrapper : public TypeErased { public: Wrapper(T value) : value(value) {} void print() const override { std::cout << value << std::endl; } private: T value; }; int main() { std::vector<std::shared_ptr<TypeErased>> vec; vec.push_back(std::make_shared<Wrapper<int>>(10)); vec.push_back(std::make_shared<Wrapper<double>>(3.14)); for (const auto& item : vec) { item->print(); } return 0; } 

    Explanation: Use a TypeErased base class to handle different template types through type-erasure.

  4. "How to use std::variant to store multiple types in a std::vector?"

    Description: Use std::variant to hold different template types in a std::vector.

    Code:

    #include <vector> #include <variant> #include <iostream> template <typename T> class MyClass { public: MyClass(T value) : value(value) {} void print() const { std::cout << value << std::endl; } private: T value; }; using VariantType = std::variant<MyClass<int>, MyClass<double>>; int main() { std::vector<VariantType> vec; vec.emplace_back(MyClass<int>(10)); vec.emplace_back(MyClass<double>(3.14)); for (const auto& item : vec) { std::visit([](const auto& obj) { obj.print(); }, item); } return 0; } 

    Explanation: Use std::variant to store different types and std::visit to handle type-specific operations.

  5. "How to use std::any for storing different template types in a std::vector?"

    Description: Use std::any to store different types in a std::vector, but you need to handle type casting when retrieving values.

    Code:

    #include <vector> #include <any> #include <iostream> template <typename T> class MyClass { public: MyClass(T value) : value(value) {} void print() const { std::cout << value << std::endl; } private: T value; }; int main() { std::vector<std::any> vec; vec.emplace_back(MyClass<int>(10)); vec.emplace_back(MyClass<double>(3.14)); for (const auto& item : vec) { if (auto* obj = std::any_cast<MyClass<int>>(&item)) { obj->print(); } else if (auto* obj = std::any_cast<MyClass<double>>(&item)) { obj->print(); } } return 0; } 

    Explanation: Use std::any for type-erasure, and std::any_cast to retrieve and handle specific types.

  6. "How to create a std::vector containing different template class instances with type traits?"

    Description: Use type traits to handle different types stored in a std::vector.

    Code:

    #include <vector> #include <memory> #include <iostream> #include <type_traits> template <typename T> class MyClass { public: MyClass(T value) : value(value) {} void print() const { std::cout << value << std::endl; } private: T value; }; template <typename T> void print_vector(const std::vector<std::shared_ptr<MyClass<T>>>& vec) { for (const auto& item : vec) { item->print(); } } int main() { std::vector<std::shared_ptr<void>> vec; vec.push_back(std::make_shared<MyClass<int>>(10)); vec.push_back(std::make_shared<MyClass<double>>(3.14)); // Cast and print based on type traits for (const auto& item : vec) { if (auto p = std::dynamic_pointer_cast<MyClass<int>>(item)) { p->print(); } else if (auto p = std::dynamic_pointer_cast<MyClass<double>>(item)) { p->print(); } } return 0; } 

    Explanation: Use std::dynamic_pointer_cast to safely cast and handle objects of different types.

  7. "How to manage a std::vector of different template class types with std::tuple?"

    Description: Use std::tuple to store different template types in a std::vector.

    Code:

    #include <vector> #include <tuple> #include <iostream> template <typename T> class MyClass { public: MyClass(T value) : value(value) {} void print() const { std::cout << value << std::endl; } private: T value; }; int main() { std::vector<std::tuple<MyClass<int>, MyClass<double>>> vec; vec.emplace_back(MyClass<int>(10), MyClass<double>(3.14)); for (const auto& item : vec) { std::get<0>(item).print(); std::get<1>(item).print(); } return 0; } 

    Explanation: Use std::tuple to group multiple types together within a std::vector.

  8. "How to use std::vector with a templated base class and derived classes for different types?"

    Description: Use a templated base class and derived classes for handling different types in a std::vector.

    Code:

    #include <vector> #include <memory> #include <iostream> template <typename T> class Base { public: virtual ~Base() = default; virtual void print() const = 0; }; template <typename T> class Derived : public Base<T> { public: Derived(T value) : value(value) {} void print() const override { std::cout << value << std::endl; } private: T value; }; int main() { std::vector<std::shared_ptr<Base<int>>> vec; vec.push_back(std::make_shared<Derived<int>>(10)); vec.push_back(std::make_shared<Derived<double>>(3.14)); // Cast required for (const auto& item : vec) { item->print(); } return 0; } 

    Explanation: Use a templated base class to store and manage different types in a std::vector.

  9. "How to handle std::vector containing various template class instances with custom visitor functions?"

    Description: Use custom visitor functions to manage different types in a std::vector containing template class instances.

    Code:

    #include <vector> #include <memory> #include <iostream> #include <variant> template <typename T> class MyClass { public: MyClass(T value) : value(value) {} void print() const { std::cout << value << std::endl; } private: T value; }; using VariantType = std::variant<MyClass<int>, MyClass<double>>; void visit(const VariantType& var) { std::visit([](const auto& obj) { obj.print(); }, var); } int main() { std::vector<VariantType> vec; vec.emplace_back(MyClass<int>(10)); vec.emplace_back(MyClass<double>(3.14)); for (const auto& item : vec) { visit(item); } return 0; } 

    Explanation: Define a custom visitor function to process various types stored in std::variant.

  10. "How to use a std::vector to store pointers to template classes of different types with type safety?"

    Description: Store pointers to template classes of different types in a std::vector while ensuring type safety through careful management.

    Code:

    #include <vector> #include <memory> #include <iostream> template <typename T> class MyClass { public: MyClass(T value) : value(value) {} void print() const { std::cout << value << std::endl; } private: T value; }; int main() { std::vector<std::unique_ptr<void, void(*)(void*)>> vec; auto deleter = [](void* ptr) { delete static_cast<MyClass<int>*>(ptr); }; vec.emplace_back(new MyClass<int>(10), deleter); for (auto& item : vec) { static_cast<MyClass<int>*>(item.get())->print(); } return 0; } 

    Explanation: Use std::unique_ptr with a custom deleter to manage pointers to different template classes safely.


More Tags

angular-ngfor dom appstore-approval fullscreen object-detection-api traversal persian sql-job internal-tables service

More Programming Questions

More Mixtures and solutions Calculators

More Weather Calculators

More Cat Calculators

More Date and Time Calculators