Поддержка декомпозиции при объявлении (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. Выражения свертки (Fold expressions)

Перегрузка и специализация шаблонных функций.