Возможно ли получить значения полей без рефлексии (вроде да)?
От: Shmj Ниоткуда  
Дата: 15.09.24 07:23
Оценка:
Как это работает в boost/pfr?

#include <boost/pfr.hpp>
#include <iostream>
#include <tuple>

struct MyStruct {
    int a;
    float b;
    double c;
};

int main() {
    MyStruct s{1, 2.0f, 3.0};
    
    // Получение значения полей по индексу
    std::cout << boost::pfr::get<0>(s) << std::endl; // Выводит: 1
    std::cout << boost::pfr::get<1>(s) << std::endl; // Выводит: 2.0
    std::cout << boost::pfr::get<2>(s) << std::endl; // Выводит: 3.0

    // Итерация по полям с использованием std::tuple
    boost::pfr::for_each_field(s, [](const auto& field) {
        std::cout << field << std::endl;
    });

    return 0;
}


?

Как примерно это возможно?
Re: Возможно ли получить значения полей без рефлексии (вроде да)?
От: vopl Россия  
Дата: 15.09.24 07:33
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Как это работает в boost/pfr?


S>
S>#include <boost/pfr.hpp>
S>#include <iostream>
S>#include <tuple>

S>struct MyStruct {
S>    int a;
S>    float b;
S>    double c;
S>};

S>int main() {
S>    MyStruct s{1, 2.0f, 3.0};
    
S>    // Получение значения полей по индексу
S>    std::cout << boost::pfr::get<0>(s) << std::endl; // Выводит: 1
S>    std::cout << boost::pfr::get<1>(s) << std::endl; // Выводит: 2.0
S>    std::cout << boost::pfr::get<2>(s) << std::endl; // Выводит: 3.0

S>    // Итерация по полям с использованием std::tuple
S>    boost::pfr::for_each_field(s, [](const auto& field) {
S>        std::cout << field << std::endl;
S>    });

S>    return 0;
S>}
S>


S>?


S>Как примерно это возможно?


Несколько лет назад эта тема хайповалась, в сети наверняка остались артфакты того хайпа, и на русском языке в том числе, если не ошибаюсь, Яндекс/Полухин. Погугли по словам "magic get"
Re[2]: Возможно ли получить значения полей без рефлексии (вроде да)?
От: Shmj Ниоткуда  
Дата: 15.09.24 07:58
Оценка:
Здравствуйте, vopl, Вы писали:

V>Несколько лет назад эта тема хайповалась, в сети наверняка остались артфакты того хайпа, и на русском языке в том числе, если не ошибаюсь, Яндекс/Полухин. Погугли по словам "magic get"


Это вот это: https://github.com/apolukhin/magic_get

?

Тоже использует boost/pfr.hpp

Мне для любопытства бы какой краткий пример, чтобы без изучения тонны исходников этого pfr.hpp понять как примерно такое удалось сделать.
Re[3]: Возможно ли получить значения полей без рефлексии (вроде да)?
От: kov_serg Россия  
Дата: 15.09.24 09:30
Оценка: 6 (1) +1
Здравствуйте, Shmj, Вы писали:

S>Мне для любопытства бы какой краткий пример, чтобы без изучения тонны исходников этого pfr.hpp понять как примерно такое удалось сделать.


https://akrzemi1.wordpress.com/2020/10/01/reflection-for-aggregates
https://stackoverflow.com/questions/77464428/how-does-boost-pfr-get-the-names-of-fields-of-a-struct
Re[3]: Возможно ли получить значения полей без рефлексии (вроде да)?
От: Великий Реверс google
Дата: 15.09.24 09:38
Оценка: +1
S>Мне для любопытства бы какой краткий пример, чтобы без изучения тонны исходников этого pfr.hpp понять как примерно такое удалось сделать.

есть видео на ютубе
и есть статья на хабре
разжевано для шмыг

если шмыга на найдет самостоятельно
то предлагаю шмыга слиться с раздела cpp навсегда
и не флудить более своими бредотопиками
Re[4]: Возможно ли получить значения полей без рефлексии (вроде да)?
От: Shmj Ниоткуда  
Дата: 15.09.24 14:42
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>https://akrzemi1.wordpress.com/2020/10/01/reflection-for-aggregates

_>https://stackoverflow.com/questions/77464428/how-does-boost-pfr-get-the-names-of-fields-of-a-struct

Во, спасибо. Получается такой код:

#include <iostream>
#include <string>
#include <tuple>
#include <type_traits>

struct init
{
  template <typename T> operator T(); // never defined
};

template <unsigned I>
struct tag : tag<I - 1>
{
};
 
template <>
struct tag<0>
{
    
};

template <typename T>
constexpr auto size_(tag<4>) -> decltype(T{init{}, init{}, init{}, init{}}, 0u)
{
    return 4u;
}
 
template <typename T>
constexpr auto size_(tag<3>) -> decltype(T{init{}, init{}, init{}}, 0u)
{
    return 3u;
}
 
template <typename T>
constexpr auto size_(tag<2>) -> decltype(T{init{}, init{}}, 0u)
{
    return 2u;
}
 
template <typename T>
constexpr auto size_(tag<1>) -> decltype(T{init{}}, 0u)
{
    return 1u;
}
 
template <typename T>
constexpr auto size_(tag<0>) -> decltype(T{}, 0u)
{
    return 0u;
}
 
template <typename T>
constexpr size_t size()
{
  static_assert(std::is_aggregate_v<T>);
  return size_<T>(tag<4>{}); // highest supported number
}

template <typename T, typename F>
void for_each_member(T const& v, F f)
{
    static_assert(std::is_aggregate_v<T>);
    
    if constexpr (size<T>() == 4u)
    {
        const auto& [m0, m1, m2, m3] = v;
        f(m0); f(m1); f(m2); f(m3);
    }
    else if constexpr (size<T>() == 3u)
    {
        const auto& [m0, m1, m2] = v;
        f(m0); f(m1); f(m2);
    }
    else if constexpr (size<T>() == 2u)
    {
        const auto& [m0, m1] = v;
        f(m0); f(m1);
    }
    else if constexpr (size<T>() == 1u)
    {
        const auto& [m0] = v;
        f(m0);
    }
}

struct Record
{
    std::string name;
    int         age;
    double      salary;
};

struct Point
{
    int x;
    int y;
};

int main()
{
    Point pt{2, 3};
    Record rec {"Baggins", 111, 999.99};
    
    auto print = [](auto const& member)
    {
        std::cout << member << " ";
    };

    for_each_member(rec, print);
    std::cout << '\n';
    for_each_member(pt, print);
    std::cout << '\n';
}


И основа всего — т.н. structured binding — или структурное связывание. Я даже не слышал о таком в контексте C++.

const auto& [m0, m1, m2, m3] = v;


Весьма.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.