История изменений
Исправление 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
.