Open blacktea opened 1 year ago
Хотелось бы увидеть пример реализации этой функции (или, по крайней мере, её объявление)
Что-то подобное можно реализовать только для std::tuple<T, T, ..., T>
Что-то подобное можно реализовать только для
std::tuple<T, T, ..., T>
Чисто теоретически, то можно реализовать возвращая std::variant<A,B,C,T>\ANY из оператора [], вот только код легче не станет.
Это можно было бы элегантно решить если бы параметр функции consteval
функции был бы constant expression
.
Уже есть бумага https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1045r0.html, где предлагаю ввести constexpr
для аргумента функции.
void f(constexpr int x) {
static_assert(x == 5);
}
Кто нибудь знает, если по этому вопросу продвижение?
И ещё вопрос, почему для consteval
функций аргументы не являются constant expression
?
Т.е. в чём сложность сделать след. код компилируемым?
consteval void f(int x) {
static_assert(x == 5);
}
Таким образом предлагаемый мной operator[]
должен быть consteval
. Иначе, как выше заметили это не реализовать или не имеет практического смысла.
Что то похожее спрашивают на SO https://stackoverflow.com/questions/56130792/will-consteval-functions-allow-template-parameters-dependent-on-function-argumen.
Если хочется только упростить синтаксис, то можно написать свою функцию forEach:
#include <cstddef>
#include <utility>
#include <tuple>
#include <iostream>
template<class Functor, class... Args>
inline void forEach(std::tuple<Args...> &tuple, Functor f) {
impl::forEach(tuple, f, std::make_integer_sequence<sizeof...(Args)>{});
}
// перегрузки
namespace impl {
template<class Functor, class... Args, std::size_t... Is>
void forEach(std::tuple<Args...> &tuple, Functor f, std::integer_sequence<Is...>) {
(f(tuple.get<Is>, Is), ...);
}
// перегрузки
}
void test() {
std::tuple<int, std::string> tuple { 10, "Hello, World!" };
forEach(tuple, [](auto obj, auto i) {
std::cout << "Iteration: " << i << std::endl
<< "Data: " << obj << std::endl;
});
}
Если это требуется для обращения по индексам, которые известны только в рантайме, проще будет написать свой tuple.
Проблема заключается в том, что tuple'ы обычно реализуются наследованием от n структур, которые называют tuple leaf'ами, следовательно, доступ к m-ому элементу требует static_cast
'а к какому-нибудь условному
(namespace)::(странное имя)::__tuple_leaf<(namespace)::(странное имя)::__tuple_traits::type_table<m>, m>
, а m является параметром шаблона, она должна быть известна в compile-time'е.
Что же делать? Пусть tuple будет состаять из сырого байтового массива размером в (sizeof(Pack) + ... + 0)
, где Pack - наши типы (компилятор все выровняет сам). И вызывать конструкторы и деструкторы вручную. А таблицу offset'ов иметь в рантайме, по хешу имени типа. И с индесами тоже самое. Правда тип для поиска по индеку все рано придется указать явно.
А следующий вариант подойдёт:
auto [... elements] = some_tuple;
elemets...[I] // <- можно обращаться по индексу
Идея Предлагаю добавить функцию
operator[](size_t)
в класс std::tuple. Функция, в отличии от std::get, принимает аргумент - индекс значения. Это очень упростит пользовательский код т.к. постоянно набирать std::get<>(tuple) - жутко не удобно.Пример:
Тоже самое, сейчас: