I'm a new C++ user from the Java world. Here is the context: Different class needs to implement foo()
function from Base
class. But this function has different combination of my_type
as input. I'm feeling using something like std::get<2>(input[1])
everywhere in the code is not easy to read and understand. Is there a elegant way to access content in an std::variant? Demo https://shorturl.at/tLQV3
#include <iostream>
#include <variant>
#include <vector>
using my_type = std::variant<int, float, bool>;
struct Base {
virtual void foo(std::vector<my_type>) = 0;
virtual ~Base() {};
};
struct B : Base {
static constexpr int kMetricRawDataTypes[] = {2,2,2,2};
void foo(std::vector<my_type> input) {
bool num_0 = std::get<2>(input[0]); // Question1.1 - is there any more elegant way to access the value?
bool num_1 = std::get<2>(input[1]);
bool num_2 = std::get<2>(input[2]);
bool num_3 = std::get<2>(input[3]);
std::cout << "input " << num_0 << " " << num_1 << " " << num_2 << " " << num_3 << std::endl;
}
};
struct A : Base {
static constexpr int kMetricRawDataTypes[] = {1, 2, 0, 1};
void foo(std::vector<my_type> input) {
float num_0 = std::get<1>(input[0]); // Question 1.2 - is there any more elegant way to access the value?
bool num_1 = std::get<2>(input[1]);
int num_2 = std::get<0>(input[2]);
float num_3 = std::get<1>(input[3]);
std::cout << "input " << num_0 << " " << num_1 << " " << num_2 << " " << num_3 << std::endl;
}
};
int main() {
my_type num1 = 1.0f;
my_type num2 = true;
my_type num3 = 5;
my_type num4 = 3.0f;
std::vector<my_type> input = {num1, num2, num3, num4};
A a;
a.foo(input);
return 0;
}
I feel there should be good solution using template. Please advise!
I'd use the validate
function in my old answer as input and rewrite it slightly to fit your new class definition. Then to print the contained types, you could fold over operator,
. To only have to implement foo
once, you could put that in a CRTP base for A
and B
. I've chosen to make the validate
function a member of the CRTP base here.
#include <iostream>
#include <variant>
#include <vector>
using my_type = std::variant<int, float, bool>;
struct Base {
virtual ~Base() = default;
virtual void foo(const std::vector<my_type>& input) const = 0;
};
template<class T> // A CRTP base for A and B
struct foo_impl : Base {
bool validate(const std::vector<my_type>& input) const {
return input.size() == std::size(T::kMetricRawDataTypes)
&& [&]<std::size_t... Is>(std::index_sequence<Is...>) {
// fold over && :
return (... && (input[Is].index() ==
T::kMetricRawDataTypes[Is]));
}(std::make_index_sequence<std::size(T::kMetricRawDataTypes)>());
}
void foo(const std::vector<my_type>& input) const override {
if(validate(input)) {
std::cout << "input";
[&]<std::size_t... Is>(std::index_sequence<Is...>) {
// fold over , (comma) to print:
((std::cout << ' ' <<
std::get<T::kMetricRawDataTypes[Is]>(input[Is])),
...);
}(std::make_index_sequence<std::size(T::kMetricRawDataTypes)>());
std::cout << '\n';
} else {
std::cout << "not valid\n";
}
}
};
struct A : foo_impl<A> { // inherit with `A` as a template parameter
static constexpr int kMetricRawDataTypes[] = {1, 2, 0, 1};
};
struct B : foo_impl<B> { // inherit with `B` as a template parameter
static constexpr int kMetricRawDataTypes[] = {2, 2, 2, 2};
};