Почему `std :: visit` так неэффективен?C++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Почему `std :: visit` так неэффективен?

Сообщение Anonymous »

Я нашел, что использует std :: variant +

Код: Выделить всё

std::visit
неэффективен (производительность почти как виртуальная функция), но когда я заменяю std :: view by x.index () , производительность так же лучше, как CRTP .
my -код:

Код: Выделить всё

#include 
#include 
#include 
#include 
#include 

namespace variant_shapes {
// 圆形实现 - 不使用虚函数
class Circle {
private:
double radius_;
public:
explicit Circle(double radius) : radius_(radius) {}

double area() const {
return M_PI * radius_ * radius_;
}

double getRadius() const { return radius_; }
};

// 矩形实现 - 不使用虚函数
class Rectangle {
private:
double width_;
double height_;
public:
Rectangle(double width, double height) : width_(width), height_(height) {}

double area() const {
return width_ * height_;
}

double getWidth() const { return width_; }
double getHeight() const { return height_; }
};
}

// 添加一个直接使用 if constexpr 的基准测试
static void BM_StaticDispatch(benchmark::State& state) {
std::vector shapes;
shapes.reserve(1000);

for (int i = 0; i < 1000; ++i) {
if (i % 2 == 0) {
shapes.emplace_back(variant_shapes::Circle(5.0));
} else {
shapes.emplace_back(variant_shapes::Rectangle(4.0, 6.0));
}
}
auto visitor = [](auto &&arg) -> double
{
using T = std::decay_t;

if constexpr (std::is_same_v)
{
return arg.area();
}
else if constexpr (std::is_same_v)
{
return arg.area();
}

};

for (auto _ : state) {
double totalArea = 0.0;
for (const auto& s : shapes) {
totalArea += std::visit(visitor, s);
}
benchmark::DoNotOptimize(totalArea);
}
}
BENCHMARK(BM_StaticDispatch);

// std::variant + std::visit 基准测试
// 使用 if constexpr 的静态分派函数
template
double get_area(const T& shape) {
if constexpr (std::is_same_v) {
return shape.area();
} else if constexpr (std::is_same_v) {
return shape.area();
}
return 0.0; // 不应该到达这里
}
static void BM_StaticDispatch2(benchmark::State& state) {
std::vector shapes;
shapes.reserve(1000);

for (int i = 0; i < 1000; ++i) {
if (i % 2 == 0) {
shapes.emplace_back(variant_shapes::Circle(5.0));
} else {
shapes.emplace_back(variant_shapes::Rectangle(4.0, 6.0));
}
}
auto visitor = [](auto &&arg) -> double
{
using T = std::decay_t;

if constexpr (std::is_same_v)
{
return arg.area();
}
else if constexpr (std::is_same_v)
{
return arg.area();
}

};

for (auto _ : state) {
double totalArea = 0.0;
for (const auto& s : shapes) {
totalArea += s.index() == 0
? get_area(std::get(s))
: get_area(std::get(s));
}
benchmark::DoNotOptimize(totalArea);
}
}
BENCHMARK(BM_StaticDispatch2);
Ссылка на тест на производительность: Quick C ++ Benchmark.

Подробнее здесь: https://stackoverflow.com/questions/796 ... nefficient
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»