std::initializer_list
in C++ is designed to handle homogeneous data types, meaning all elements must be of the same type. However, there are scenarios where you might want to work with heterogeneous data. Although std::initializer_list
itself cannot handle heterogeneous types, there are alternative approaches to achieve similar functionality.
One common approach is to use std::tuple
, which can store elements of different types:
#include <iostream>
#include <tuple>
int main() {
std::tuple<int, double, std::string> myTuple{
1, 2.5, "Hello"};
std::cout << std::get<0>(myTuple) << ", "
<< std::get<1>(myTuple) << ", "
<< std::get<2>(myTuple);
}
1, 2.5, Hello
In this example, std::tuple
allows storing an int
, double
, and std::string
together. You can access each element using std::get<>()
.
If you need a container that can dynamically handle different types, consider using std::variant
or a base class with pointers to derived classes:
#include <iostream>
#include <variant>
#include <vector>
int main() {
std::vector<std::variant<
int, double, std::string>
> vec{1, 2.5, "Hello"};
for (const auto& elem : vec) {
std::visit([](auto&& arg) {
std::cout << arg << ", ";
}, elem);
}
}
1, 2.5, Hello
std::variant
can hold any one of the specified types at a time. Using std::visit
, you can apply a visitor function to handle each type.
For more complex scenarios, you might use a base class with a polymorphic approach:
#include <iostream>
#include <vector>
#include <memory>
class Base {
public:
virtual void Log() const = 0;
virtual ~Base() = default;
};
class DerivedInt : public Base {
int value;
public:
DerivedInt(int val)
: value{val} {}
void Log() const override {
std::cout << value << ' ';
}
};
class DerivedDouble : public Base {
double value;
public:
DerivedDouble(double val)
: value{val} {}
void Log() const override {
std::cout << value << ' ';
}
};
class DerivedString : public Base {
std::string value;
public:
DerivedString(std::string val)
: value{val} {}
void Log() const override {
std::cout << value << ' ';
}
};
int main() {
std::vector<std::unique_ptr<Base>> vec;
vec.push_back(
std::make_unique<DerivedInt>(1)
);
vec.push_back(
std::make_unique<DerivedDouble>(2.5)
);
vec.push_back(
std::make_unique<DerivedString>("Hello")
);
for (const auto& elem : vec) {
elem->Log();
}
}
1 2.5 Hello
This polymorphic approach allows you to store different types in a container, each derived from a common base class. This technique is flexible but requires more boilerplate code.
While std::initializer_list
is limited to homogeneous types, using std::tuple
, std::variant
, or polymorphism provides powerful alternatives to handle heterogeneous data effectively.
Answers to questions are automatically generated and may not have been reviewed.
A quick guide to creating objects using lists, including std::initializer_list
, aggregate and designated initialization