LINUX.ORG.RU

История изменений

Исправление fsb4000, (текущая версия) :

Не думаю, что второй колбэк для юзер симпатичней, он его напугает скорее, а он их должен писать сам.

нужно изучать С++. Вариант норм.

В минимальном виде callback выглядит так:

auto callback = [](auto v){use(v);};
std::visit(callback, var);

В чуть большем:

auto callback = overloaded {
            [](auto arg) { std::cout << arg << ' '; },
            [](double arg) { std::cout << std::fixed << arg << ' '; },
            [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; }
        };
std::visit(callback, var);

В полном виде:

auto callback = [](auto&& arg) {
    using T = std::decay_t<decltype(arg)>;
    if constexpr (std::is_same_v<T, int>)
        std::cout << "int with value " << arg << '\n';
    else if constexpr (std::is_same_v<T, long>)
        std::cout << "long with value " << arg << '\n';
    else if constexpr (std::is_same_v<T, double>)
       std::cout << "double with value " << arg << '\n';
    else if constexpr (std::is_same_v<T, std::string>)
       std::cout << "std::string with value " << std::quoted(arg) << '\n';
    else 
      static_assert(always_false_v<T>, "non-exhaustive visitor!");
};
std::visit(callback, var);

или так

struct visitor {
    int operator()(int i) const {
        return i;
    }
    int operator()(const Neg& n) const {
        return -eval(*n.expr);
    }
    int operator()(const Add& a) const {
        return eval(*a.lhs) + eval(*a.rhs);
    }
    int operator()(const Mul& m) const {
        return eval(*m.lhs) * eval(*m.rhs);
    }
};
std::visit(visitor{}, var);

В любом случае не хуже свича.

union норм, когда мы можем по каким-то другим критериям понять какой тип в нём хранится и нам не нужен tag. Как, например, в std::string мы можем понять по значению последнего байта строка на стеке или в куче(так как адрес должен быть выровнен, то при куче будет обязательно 0, а на стеке мы можем присвоить значение последнего байта 1. Чтобы не было UB при проверке(так как мы не знаем какой тип union активный) используем std::bit_cast.

Исправление fsb4000, :

Не думаю, что второй колбэк для юзер симпатичней, он его напугает скорее, а он их должен писать сам.

нужно изучать С++. Вариант норм.

В минимальном виде callback выглядит так:

auto callback = [](auto v){use(v);};
std::visit(callback, var);

В чуть большем:

auto callback = overloaded {
            [](auto arg) { std::cout << arg << ' '; },
            [](double arg) { std::cout << std::fixed << arg << ' '; },
            [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; }
        };
std::visit(callback, var);

В полном виде:

auto callback = [](auto&& arg) {
            using T = std::decay_t<decltype(arg)>;
            if constexpr (std::is_same_v<T, int>)
                std::cout << "int with value " << arg << '\n';
            else if constexpr (std::is_same_v<T, long>)
                std::cout << "long with value " << arg << '\n';
            else if constexpr (std::is_same_v<T, double>)
                std::cout << "double with value " << arg << '\n';
            else if constexpr (std::is_same_v<T, std::string>)
                std::cout << "std::string with value " << std::quoted(arg) << '\n';
            else 
                static_assert(always_false_v<T>, "non-exhaustive visitor!");
        };
std::visit(callback, var);

или так

struct visitor {
    int operator()(int i) const {
        return i;
    }
    int operator()(const Neg& n) const {
        return -eval(*n.expr);
    }
    int operator()(const Add& a) const {
        return eval(*a.lhs) + eval(*a.rhs);
    }
    int operator()(const Mul& m) const {
        return eval(*m.lhs) * eval(*m.rhs);
    }
};
std::visit(visitor{}, var);

В любом случае не хуже свича.

union норм, когда мы можем по каким-то другим критериям понять какой тип в нём хранится и нам не нужен tag. Как, например, в std::string мы можем понять по значению последнего байта строка на стеке или в куче(так как адрес должен быть выровнен, то при куче будет обязательно 0, а на стеке мы можем присвоить значение последнего байта 1. Чтобы не было UB при проверке(так как мы не знаем какой тип union активный) используем std::bit_cast.

Исправление fsb4000, :

Не думаю, что второй колбэк для юзер симпатичней, он его напугает скорее, а он их должен писать сам.

нужно изучать С++. Вариант норм.

В минимальном виде callback выглядит так:

auto callback = [](auto v){use(v);};
std::visit(callback, var);

В чуть большем:

auto callback = overloaded {
            [](auto arg) { std::cout << arg << ' '; },
            [](double arg) { std::cout << std::fixed << arg << ' '; },
            [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; }
        };
std::visit(callback, var);

В полном виде:

auto callback = [](auto&& arg) {
            using T = std::decay_t<decltype(arg)>;
            if constexpr (std::is_same_v<T, int>)
                std::cout << "int with value " << arg << '\n';
            else if constexpr (std::is_same_v<T, long>)
                std::cout << "long with value " << arg << '\n';
            else if constexpr (std::is_same_v<T, double>)
                std::cout << "double with value " << arg << '\n';
            else if constexpr (std::is_same_v<T, std::string>)
                std::cout << "std::string with value " << std::quoted(arg) << '\n';
            else 
                static_assert(always_false_v<T>, "non-exhaustive visitor!");
        };
std::visit(callback, var);

или так

    struct visitor {
        int operator()(int i) const {
            return i;
        }
        int operator()(const Neg& n) const {
            return -eval(*n.expr);
        }
        int operator()(const Add& a) const {
            return eval(*a.lhs) + eval(*a.rhs);
        }
        int operator()(const Mul& m) const {
            return eval(*m.lhs) * eval(*m.rhs);
        }
    };
std::visit(visitor{}, var);

В любом случае не хуже свича.

union норм, когда мы можем по каким-то другим критериям понять какой тип в нём хранится и нам не нужен tag. Как, например, в std::string мы можем понять по значению последнего байта строка на стеке или в куче(так как адрес должен быть выровнен, то при куче будет обязательно 0, а на стеке мы можем присвоить значение последнего байта 1. Чтобы не было UB при проверке(так как мы не знаем какой тип union активный) используем std::bit_cast.

Исправление fsb4000, :

Не думаю, что второй колбэк для юзер симпатичней, он его напугает скорее, а он их должен писать сам.

нужно изучать С++. Вариант норм.

В минимальном виде callback выглядит так:

auto callback = [](auto v){use(v);};

В чуть большем:

auto callback = overloaded {
            [](auto arg) { std::cout << arg << ' '; },
            [](double arg) { std::cout << std::fixed << arg << ' '; },
            [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; }
        };

В полном виде:

auto callback = [](auto&& arg) {
            using T = std::decay_t<decltype(arg)>;
            if constexpr (std::is_same_v<T, int>)
                std::cout << "int with value " << arg << '\n';
            else if constexpr (std::is_same_v<T, long>)
                std::cout << "long with value " << arg << '\n';
            else if constexpr (std::is_same_v<T, double>)
                std::cout << "double with value " << arg << '\n';
            else if constexpr (std::is_same_v<T, std::string>)
                std::cout << "std::string with value " << std::quoted(arg) << '\n';
            else 
                static_assert(always_false_v<T>, "non-exhaustive visitor!");
        }

или так

    struct visitor {
        int operator()(int i) const {
            return i;
        }
        int operator()(const Neg& n) const {
            return -eval(*n.expr);
        }
        int operator()(const Add& a) const {
            return eval(*a.lhs) + eval(*a.rhs);
        }
        int operator()(const Mul& m) const {
            return eval(*m.lhs) * eval(*m.rhs);
        }
    };

В любом случае не хуже свича.

union норм, когда мы можем по каким-то другим критериям понять какой тип в нём хранится и нам не нужен tag. Как, например, в std::string мы можем понять по значению последнего байта строка на стеке или в куче(так как адрес должен быть выровнен, то при куче будет обязательно 0, а на стеке мы можем присвоить значение последнего байта 1. Чтобы не было UB при проверке(так как мы не знаем какой тип union активный) используем std::bit_cast.

Исходная версия fsb4000, :

Не думаю, что второй колбэк для юзер симпатичней, он его напугает скорее, а он их должен писать сам.

нужно изучать С++. Вариант норм.

В минимальном виде callback выглядит так:

auto callback = [](auto v){use(v);};

В чуть большем:

auto callback = overloaded {
            [](auto arg) { std::cout << arg << ' '; },
            [](double arg) { std::cout << std::fixed << arg << ' '; },
            [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; }
        };

В полном виде:

auto callback = [](auto&& arg) {
            using T = std::decay_t<decltype(arg)>;
            if constexpr (std::is_same_v<T, int>)
                std::cout << "int with value " << arg << '\n';
            else if constexpr (std::is_same_v<T, long>)
                std::cout << "long with value " << arg << '\n';
            else if constexpr (std::is_same_v<T, double>)
                std::cout << "double with value " << arg << '\n';
            else if constexpr (std::is_same_v<T, std::string>)
                std::cout << "std::string with value " << std::quoted(arg) << '\n';
            else 
                static_assert(always_false_v<T>, "non-exhaustive visitor!");
        }

или так

    struct visitor {
        int operator()(int i) const {
            return i;
        }
        int operator()(const Neg& n) const {
            return -eval(*n.expr);
        }
        int operator()(const Add& a) const {
            return eval(*a.lhs) + eval(*a.rhs);
        }
        int operator()(const Mul& m) const {
            return eval(*m.lhs) * eval(*m.rhs);
        }
    };

В любом случае не хуже свича.

union норм, когда мы можем понять по каким-то другим критериям понять какой тип в нём хранится и нам не нужен tag. Как например в std::string мы можем понять по значению последнего байта строка на стеке или в куче(так как адрес должен быть выровнен, то при куче будет обязательно 0, а на стеке мы можем присвоить значение последнего байта. Чтобы не было UB при проверке(так как мы не знаем какой тип union активный) используем std::bit_cast.