Поддержка декомпозиции при объявлении (structural bindings) для классов
На основе статьи https://blog.tartanllama.xyz/structured-bindings/.
С++17 добавил к языку декомпозицию при объявлении, которая позволяет объявлять множество переменных, инициализированных из подобных кортежу объектов:
tuple<T1,T2,T3> f(/*...*/) { /*...*/ return {a,b,c}; }
auto [x,y,z] = f(); // x имеет тип T1, y имеет тип T2, z имеет тип T3
Это мощный и выразительный механизм языка, имеющий существенное ограничение - декомпозиция работает только с public - членами передаваемой структуры. Поэтому попытка доступа к private - членам класса вызовет соответствующую ошибку при компиляции.
Обойти это ограничение можно - необходимо определить специализации std::tuple_size и std::tumpe_element для своего класса и определить шаблонную функцию-член get этого класса (либо дружественную c тем же именем).
Покажем эту технику на примере
class Person
{
std::string name;
std::size_t age;
public:
Person()
{
name = "Eugene";
age = 56;
}
template <std::size_t N>
decltype(auto) get() const
{
if constexpr (N == 0)
return std::string_view{name};
else if constexpr (N == 1)
return age;
}
};
В класс Person добавлена функция-член get(), которая возвращает значение поля по определенному пользователем индексу и попутно преобразовывает std::string в std::string_view.
В пространстве имен std определяем специализации tuple_size и tuple_element следующим образом:
namespace std
{
template<>
struct tuple_size<Person> : std::integral_constant<std::size_t, 2> {};
template<std::size_t N>
struct tuple_element<N, Person> {
using type = decltype(std::declval<Person>().get<N>());
};
}
Используем полученный результат:
int main()
{
Person c;
auto [n, a] = c;
std::cout << " n = " << n << " a = " << a << endl;
return 0;
}
Вывод:
n = Eugene, a = 56
С++17 добавил к языку декомпозицию при объявлении, которая позволяет объявлять множество переменных, инициализированных из подобных кортежу объектов:
tuple<T1,T2,T3> f(/*...*/) { /*...*/ return {a,b,c}; }
auto [x,y,z] = f(); // x имеет тип T1, y имеет тип T2, z имеет тип T3
Это мощный и выразительный механизм языка, имеющий существенное ограничение - декомпозиция работает только с public - членами передаваемой структуры. Поэтому попытка доступа к private - членам класса вызовет соответствующую ошибку при компиляции.
Обойти это ограничение можно - необходимо определить специализации std::tuple_size и std::tumpe_element для своего класса и определить шаблонную функцию-член get этого класса (либо дружественную c тем же именем).
Покажем эту технику на примере
class Person
{
std::string name;
std::size_t age;
public:
Person()
{
name = "Eugene";
age = 56;
}
template <std::size_t N>
decltype(auto) get() const
{
if constexpr (N == 0)
return std::string_view{name};
else if constexpr (N == 1)
return age;
}
};
В класс Person добавлена функция-член get(), которая возвращает значение поля по определенному пользователем индексу и попутно преобразовывает std::string в std::string_view.
В пространстве имен std определяем специализации tuple_size и tuple_element следующим образом:
namespace std
{
template<>
struct tuple_size<Person> : std::integral_constant<std::size_t, 2> {};
template<std::size_t N>
struct tuple_element<N, Person> {
using type = decltype(std::declval<Person>().get<N>());
};
}
Используем полученный результат:
int main()
{
Person c;
auto [n, a] = c;
std::cout << " n = " << n << " a = " << a << endl;
return 0;
}
Вывод:
n = Eugene, a = 56
Комментарии
Отправить комментарий