I was following this blog and was trying to replace a dynamic polymorphism code into using std::variant and std::visit. But I can not get std::variant + std::visit to work better than a virtual struct impl. Its about 1.3-1.5x slower! (GCC 10.3 -O3 C++17)
The use case is as follows. Say we are comparing i'th and j'th row of two tables. A table could have heterogeneously typed columns. Assume we can access column buffers. What I am doing is testing,
def IndexEqual(Table:A, Table:B, int:i, int:j):
for c in range(A.num_cols):
if not A.column(c)[i] == B.column(c)[j]:
return False
return True
for dynamic polymorphism I have the following for int and float
struct Comp{
virtual bool comp(size_t i, size_t j) const = 0;
};
struct CompI: public Comp {
CompI(const int *data_1, const int *data_2) : data1(data_1), data2(data_2) {}
const int *data1, *data2;
bool comp(size_t i, size_t j) const override {
return data1[i] == data2[j];
}
};
struct CompF: public Comp {
CompF(const float *data_1, const float *data_2) : data1(data_1), data2(data_2) {}
const float *data1, *data2;
bool comp(size_t i, size_t j) const override {
return data1[i] == data2[j];
}
};
bool IndexEqual1(const std::vector<Comp *> &comps, size_t i, size_t j) {
for (auto &&a: comps) {
if (!a->comp(i, j)) {
return false;
}
}
return true;
}
This was transformed to std::variant + std::visit as follows.
struct EqualToI {
EqualToI(const int *data_1, const int *data_2) : data1(data_1), data2(data_2) {}
const int *data1, *data2;
bool comp(size_t i, size_t j) const {
return data1[i] == data2[j];
}
};
struct EqualToF {
EqualToF(const float *data_1, const float *data_2) : data1(data_1), data2(data_2) {}
const float *data1, *data2;
bool comp(size_t i, size_t j) const {
return data1[i] == data2[j];
}
};
using var_type = typename std::variant<EqualToI, EqualToF>;
bool IndexEqual(const std::vector<var_type> &comps, size_t i, size_t j) {
for (auto &&a: comps) {
if (!std::visit([&](const auto &comp) {
return comp.comp(i, j);
}, a)) {
return false;
}
}
return true;
}
I benchmarked this here https://quick-bench.com/q/u-cBjg4hyQjOs6fKem9XSdW7LMs
Can someone one please explain why this std::variant + std::visit option is slower than the dynamic polimorphism approach? I was expecting otherwise! Is there a problem in my approach and/or benchmark?
Using
variantdoes not constitute "static polymorphism". It is still dynamic polymorphism because the compiler does not know which type will actually inhabit thevariant. Therefore, the code in question must attempt to figure out what thevariantstores at runtime, and it must dispatch those calls accordingly.Note that the article you link to also doesn't call it "static polymorphism". It emphasizes that it is merely a different form of "runtime polymorphism" from virtual functions.