GithubHelp home page GithubHelp logo

boostorg / pfr Goto Github PK

View Code? Open in Web Editor NEW
1.3K 48.0 151.0 1.2 MB

std::tuple like methods for user defined types without any macro or boilerplate code

Home Page: https://boost.org/libs/pfr

License: Boost Software License 1.0

C++ 96.72% Python 2.55% HTML 0.13% CMake 0.09% Shell 0.51%
boost std reflection cpp14 cpp17 reflections reflection-library cpp cplusplus cplusplus-14

pfr's Introduction

This is a C++14 library for very basic reflection that gives you access to structure elements by index and provides other std::tuple like methods for user defined types without any macro or boilerplate code.

Boost.PFR is a part of the Boost C++ Libraries. However, Boost.PFR is a header only library that does not depend on Boost. You can just copy the content of the "include" folder from the github into your project, and the library will work fine.

For a version of the library without boost:: namespace see PFR.

Test results

Branches Build Tests coverage More info
Develop: CI Build status Coverage Status details...
Master: CI Build status Coverage Status details...

Latest developer documentation

Motivating Example #0

#include <iostream>
#include <fstream>
#include <string>

#include "boost/pfr.hpp"

struct some_person {
  std::string name;
  unsigned birth_year;
};

int main(int argc, const char* argv[]) {
  some_person val{"Edgar Allan Poe", 1809};

  std::cout << boost::pfr::get<0>(val)                // No macro!
      << " was born in " << boost::pfr::get<1>(val);  // Works with any aggregate initializables!

  if (argc > 1) {
    std::ofstream ofs(argv[1]);
    ofs << boost::pfr::io(val);                       // File now contains: {"Edgar Allan Poe", 1809}
  }
}

Outputs:

Edgar Allan Poe was born in 1809

Run the above sample

Motivating Example #1

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

struct my_struct { // no ostream operator defined!
    int i;
    char c;
    double d;
};

int main() {
    my_struct s{100, 'H', 3.141593};
    std::cout << "my_struct has " << boost::pfr::tuple_size<my_struct>::value
        << " fields: " << boost::pfr::io(s) << "\n";
}

Outputs:

my_struct has 3 fields: {100, H, 3.14159}

Motivating Example #2

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

struct my_struct { // no ostream operator defined!
    std::string s;
    int i;
};

int main() {
    my_struct s{{"Das ist fantastisch!"}, 100};
    std::cout << "my_struct has " << boost::pfr::tuple_size<my_struct>::value
        << " fields: " << boost::pfr::io(s) << "\n";
}

Outputs:

my_struct has 2 fields: {"Das ist fantastisch!", 100}

Motivating Example #3

#include <iostream>
#include <string>

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_boost_pfr.hpp>

#include "boost/pfr/io.hpp"

namespace x3 = boost::spirit::x3;

struct ast_employee { // No BOOST_FUSION_ADAPT_STRUCT defined
    int age;
    std::string forename;
    std::string surname;
    double salary;
};

auto const quoted_string = x3::lexeme['"' >> +(x3::ascii::char_ - '"') >> '"'];

x3::rule<class employee, ast_employee> const employee = "employee";
auto const employee_def =
    x3::lit("employee")
    >> '{'
    >>  x3::int_ >> ','
    >>  quoted_string >> ','
    >>  quoted_string >> ','
    >>  x3::double_
    >>  '}'
    ;
BOOST_SPIRIT_DEFINE(employee);

int main() {
    std::string str = R"(employee{34, "Chip", "Douglas", 2500.00})";
    ast_employee emp;
    x3::phrase_parse(str.begin(),
                     str.end(),
                     employee,
                     x3::ascii::space,
                     emp);
    std::cout << boost::pfr::io(emp) << std::endl;
}

Outputs:

(34 Chip Douglas 2500)

Requirements and Limitations

See docs.

License

Distributed under the Boost Software License, Version 1.0.

pfr's People

Contributors

abutcher-gh avatar akrzemi1 avatar alexey-romanov avatar alexiprof avatar alexkaratarakis avatar apolukhin avatar ashtum avatar bryant1410 avatar caozhanhao avatar cbeck88 avatar denzor200 avatar eldiener avatar ericlemanissier avatar glenfe avatar grafikrobot avatar jatinkh25 avatar jcelerier avatar kojoley avatar markus-oberhumer avatar ofats avatar pdimov avatar zmij avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pfr's Issues

Failed to reflect containers with std::unique_ptr

Issue #27 and #30 solved the problem of reflecting std::unique_ptr
But it seems that this is not applied in case of containers.
The following snipper

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

using namespace std;

struct TestStruct {
  std::vector<std::unique_ptr<int>> prova;
};

int main()
{
  TestStruct temp;
  boost::pfr::for_each_field(temp, [](const auto& value){
  });
}

does not compile with the following error

distcc /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi-g++ --sysroot=/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi    -march=armv7-a -marm -mfpu=neon  -mfloat-abi=hard -mcpu=cortex-a9 -g -MD -MT CMakeFiles/untitled.dir/main.cpp.o -MF CMakeFiles/untitled.dir/main.cpp.o.d -o CMakeFiles/untitled.dir/main.cpp.o -c /tmp/untitled/main.cpp
distcc[16414] Warning: INCLUDE_SERVER_PORT not set - did you forget to run under 'distcc-pump'?
distcc[16414] (dcc_build_somewhere) Warning: failed to get includes from include server, preprocessing locally
distcc[16414] ERROR: compile /tmp/untitled/main.cpp on ap-ThinkPad-T520.local,lzo,cpp failed
distcc[16414] (dcc_build_somewhere) Warning: remote compilation of '/tmp/untitled/main.cpp' failed, retrying locally
distcc[16414] Warning: failed to distribute /tmp/untitled/main.cpp to ap-ThinkPad-T520.local,lzo,cpp, running locally instead
In file included from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/c++/6.3.0/vector:62:0,
                 from /tmp/untitled/main.cpp:2:
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/c++/6.3.0/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, _Args&& ...) [with _T1 = std::unique_ptr<int>; _Args = {const std::unique_ptr<int, std::default_delete<int> >&}]’:
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/c++/6.3.0/bits/stl_uninitialized.h:75:18:   required from ‘static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::unique_ptr<int>*, std::vector<std::unique_ptr<int> > >; _ForwardIterator = std::unique_ptr<int>*; bool _TrivialValueTypes = false]’
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/c++/6.3.0/bits/stl_uninitialized.h:126:15:   required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::unique_ptr<int>*, std::vector<std::unique_ptr<int> > >; _ForwardIterator = std::unique_ptr<int>*]’
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/c++/6.3.0/bits/stl_uninitialized.h:281:37:   required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::unique_ptr<int>*, std::vector<std::unique_ptr<int> > >; _ForwardIterator = std::unique_ptr<int>*; _Tp = std::unique_ptr<int>]’
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/c++/6.3.0/bits/stl_vector.h:324:31:   required from ‘std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = std::unique_ptr<int>; _Alloc = std::allocator<std::unique_ptr<int> >]’
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14_loophole.hpp:70:117:   required from ‘auto boost::pfr::detail::loophole(boost::pfr::detail::tag<TestStruct, 0u>)’
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14_loophole.hpp:118:58:   required from ‘struct boost::pfr::detail::loophole_type_list_lref<TestStruct, std::integer_sequence<unsigned int, 0u> >’
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14_loophole.hpp:152:57:   required from ‘auto boost::pfr::detail::tie_as_tuple_loophole_impl(T&) [with T = TestStruct]’
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14_loophole.hpp:255:55:   required from ‘void boost::pfr::detail::for_each_field_dispatcher(T&, F&&, std::index_sequence<I ...>) [with T = TestStruct; F = boost::pfr::for_each_field(T&&, F&&) [with T = TestStruct&; F = main()::<lambda(const auto:7&)>]::<lambda(auto:1&&)>; unsigned int ...I = {0u}; std::index_sequence<I ...> = std::integer_sequence<unsigned int, 0u>]’
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/precise/core.hpp:140:52:   required from ‘void boost::pfr::for_each_field(T&&, F&&) [with T = TestStruct&; F = main()::<lambda(const auto:7&)>]’
/tmp/untitled/main.cpp:15:4:   required from here
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/c++/6.3.0/bits/stl_construct.h:75:7: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]’
     { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/c++/6.3.0/bits/locale_conv.h:41:0,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/c++/6.3.0/locale:43,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/c++/6.3.0/iomanip:43,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/io.hpp:14,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/precise/io.hpp:17,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/precise/ops.hpp:15,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/precise.hpp:14,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr.hpp:12,
                 from /tmp/untitled/main.cpp:3:
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/c++/6.3.0/bits/unique_ptr.h:359:7: note: declared here
       unique_ptr(const unique_ptr&) = delete;
       ^~~~~~~~~~
distcc[16414] ERROR: compile /tmp/untitled/main.cpp on localhost failed
ninja: build stopped: subcommand failed.
16:10:31: The process "/home/cucchetf/tools/cmake/bin/cmake" exited with code 1.
Error while building/deploying project untitled (kit: Private SDK)
The kit Private SDK has configuration issues which might be the root cause for this problem.
When executing step "CMake Build"

Base types are returned as tuple members when using `precise` version of functions.

Here is some minimal example and output from Metashell:

using std::declval;
using namespace boost::pfr;

struct A {
  int a;
};

// metashell interaction
> decltype(structure_to_tuple(declval<A>()))
std::tuple<int>
> decltype(flat_structure_to_tuple(declval<A>()))
std::tuple<int>
// end metashell interaction, so far so good

// An empty structure with a single base
struct B : A {};

// metashell interaction
> decltype(structure_to_tuple(declval<B>()))
std::tuple<A>
> decltype(flat_structure_to_tuple(declval<B>()))
std::tuple<int>
// end metashell interaction

struct C {
  float c;
};

struct D : A, C {};
// metashell interaction
> decltype(structure_to_tuple(declval<D>()))
std::tuple<A, C>
> decltype(flat_structure_to_tuple(declval<D>()))
std::tuple<int, float>
// end metashell interaction

compiler errors with gcc-7 and clang-4

Tried to build the "Motivating Example"s.

C++14 example was okay with gcc-6.
C++14 example and C++17 example did not compile with gcc-7 and clang-4.

Note:
gcc (Ubuntu 7-20170407-0ubuntu2) 7.0.1 20170407 (experimental) [trunk revision 246759]
clang version 4.0.0-1ubuntu1 (tags/RELEASE_400/rc1)

C++14 example compiler errors (gcc 7):

gcc.compile.c++ bin/gcc-7/release/source/test_magic.o
In file included from /home/mike/workspace/magic_get/include/boost/pfr/detail/core17.hpp:11:0,
                 from /home/mike/workspace/magic_get/include/boost/pfr/precise/core.hpp:20,
                 from /home/mike/workspace/magic_get/include/boost/pfr/precise.hpp:12,
                 from /home/mike/workspace/magic_get/include/boost/pfr.hpp:12,
                 from source/test_magic.cpp:9:
/home/mike/workspace/magic_get/include/boost/pfr/detail/core17_generated.hpp: In instantiation of ‘constexpr auto boost::pfr::detail::as_tuple_impl(T&&, boost::pfr::detail::size_t_<3>) [with T = const my_struct&; boost::pfr::detail::size_t_<3> = std::integral_constant<long unsigned int, 3>]’:
/home/mike/workspace/magic_get/include/boost/pfr/detail/core17_generated.hpp:1032:43:   required from ‘constexpr auto boost::pfr::detail::as_tuple(const T&) [with T = my_struct]’
/home/mike/workspace/magic_get/include/boost/pfr/precise/io.hpp:45:69:   required from ‘void boost::pfr::write(std::basic_ostream<_CharT, _Traits>&, const T&) [with Char = char; Traits = std::char_traits<char>; T = my_struct]’
/home/mike/workspace/magic_get/include/boost/pfr/precise/ops.hpp:129:26:   required from ‘boost::pfr::detail::enable_not_ostreamable_t<std::basic_ostream<_CharT, _Traits>, T> boost::pfr::ops::operator<<(std::basic_ostream<_CharT, _Traits>&, const T&) [with Char = char; Traits = std::char_traits<char>; T = my_struct; boost::pfr::detail::enable_not_ostreamable_t<std::basic_ostream<_CharT, _Traits>, T> = std::basic_ostream<char>&]’
source/test_magic.cpp:22:27:   required from here
/home/mike/workspace/magic_get/include/boost/pfr/detail/core17_generated.hpp:57:9: error: ‘std::tuple_size<const my_struct>::value’ is not an integral constant expression
   auto& [a,b,c] = std::forward<T>(val);
         ^~~~~~~
In file included from /home/mike/workspace/magic_get/include/boost/pfr/precise/ops.hpp:15:0,
                 from /home/mike/workspace/magic_get/include/boost/pfr/precise.hpp:14,
                 from /home/mike/workspace/magic_get/include/boost/pfr.hpp:12,
                 from source/test_magic.cpp:9:
/home/mike/workspace/magic_get/include/boost/pfr/precise/io.hpp: In instantiation of ‘void boost::pfr::write(std::basic_ostream<_CharT, _Traits>&, const T&) [with Char = char; Traits = std::char_traits<char>; T = my_struct]’:
/home/mike/workspace/magic_get/include/boost/pfr/precise/ops.hpp:129:26:   required from ‘boost::pfr::detail::enable_not_ostreamable_t<std::basic_ostream<_CharT, _Traits>, T> boost::pfr::ops::operator<<(std::basic_ostream<_CharT, _Traits>&, const T&) [with Char = char; Traits = std::char_traits<char>; T = my_struct; boost::pfr::detail::enable_not_ostreamable_t<std::basic_ostream<_CharT, _Traits>, T> = std::basic_ostream<char>&]’
source/test_magic.cpp:22:27:   required from here
/home/mike/workspace/magic_get/include/boost/pfr/precise/io.hpp:45:47: error: invalid use of void expression
     detail::print_impl<0, fields_count>::print(out, detail::as_tuple(value));
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    "g++"  -ftemplate-depth-128 -march=native -ftemplate-depth=256 -std=c++17 -O3 -finline-functions -Wno-inline -Wall -fPIC  -DBOOST_ALL_DYN_LINK -DNDEBUG  -I"/home/mike/workspace/magic_get/include" -I"include" -c -o "bin/gcc-7/release/source/test_magic.o" "source/test_magic.cpp"

...failed gcc.compile.c++ bin/gcc-7/release/source/test_magic.o...

C++17 example compiler errors (gcc-7):

gcc.compile.c++ bin/gcc-7/release/source/test_magic.o
In file included from /home/mike/workspace/magic_get/include/boost/pfr/detail/core17.hpp:11:0,
                 from /home/mike/workspace/magic_get/include/boost/pfr/precise/core.hpp:20,
                 from /home/mike/workspace/magic_get/include/boost/pfr/precise.hpp:12,
                 from /home/mike/workspace/magic_get/include/boost/pfr.hpp:12,
                 from source/test_magic.cpp:9:
/home/mike/workspace/magic_get/include/boost/pfr/detail/core17_generated.hpp: In instantiation of ‘constexpr auto boost::pfr::detail::as_tuple_impl(T&&, boost::pfr::detail::size_t_<2>) [with T = const my_struct&; boost::pfr::detail::size_t_<2> = std::integral_constant<long unsigned int, 2>]’:
/home/mike/workspace/magic_get/include/boost/pfr/detail/core17_generated.hpp:1032:43:   required from ‘constexpr auto boost::pfr::detail::as_tuple(const T&) [with T = my_struct]’
/home/mike/workspace/magic_get/include/boost/pfr/precise/io.hpp:45:69:   required from ‘void boost::pfr::write(std::basic_ostream<_CharT, _Traits>&, const T&) [with Char = char; Traits = std::char_traits<char>; T = my_struct]’
/home/mike/workspace/magic_get/include/boost/pfr/precise/ops.hpp:129:26:   required from ‘boost::pfr::detail::enable_not_ostreamable_t<std::basic_ostream<_CharT, _Traits>, T> boost::pfr::ops::operator<<(std::basic_ostream<_CharT, _Traits>&, const T&) [with Char = char; Traits = std::char_traits<char>; T = my_struct; boost::pfr::detail::enable_not_ostreamable_t<std::basic_ostream<_CharT, _Traits>, T> = std::basic_ostream<char>&]’
source/test_magic.cpp:21:27:   required from here
/home/mike/workspace/magic_get/include/boost/pfr/detail/core17_generated.hpp:51:9: error: ‘std::tuple_size<const my_struct>::value’ is not an integral constant expression
   auto& [a,b] = std::forward<T>(val);
         ^~~~~
In file included from /home/mike/workspace/magic_get/include/boost/pfr/precise/ops.hpp:15:0,
                 from /home/mike/workspace/magic_get/include/boost/pfr/precise.hpp:14,
                 from /home/mike/workspace/magic_get/include/boost/pfr.hpp:12,
                 from source/test_magic.cpp:9:
/home/mike/workspace/magic_get/include/boost/pfr/precise/io.hpp: In instantiation of ‘void boost::pfr::write(std::basic_ostream<_CharT, _Traits>&, const T&) [with Char = char; Traits = std::char_traits<char>; T = my_struct]’:
/home/mike/workspace/magic_get/include/boost/pfr/precise/ops.hpp:129:26:   required from ‘boost::pfr::detail::enable_not_ostreamable_t<std::basic_ostream<_CharT, _Traits>, T> boost::pfr::ops::operator<<(std::basic_ostream<_CharT, _Traits>&, const T&) [with Char = char; Traits = std::char_traits<char>; T = my_struct; boost::pfr::detail::enable_not_ostreamable_t<std::basic_ostream<_CharT, _Traits>, T> = std::basic_ostream<char>&]’
source/test_magic.cpp:21:27:   required from here
/home/mike/workspace/magic_get/include/boost/pfr/precise/io.hpp:45:47: error: invalid use of void expression
     detail::print_impl<0, fields_count>::print(out, detail::as_tuple(value));
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    "g++"  -ftemplate-depth-128 -march=native -ftemplate-depth=256 -std=c++17 -O3 -finline-functions -Wno-inline -Wall -fPIC  -DBOOST_ALL_DYN_LINK -DNDEBUG  -I"/home/mike/workspace/magic_get/include" -I"include" -c -o "bin/gcc-7/release/source/test_magic.o" "source/test_magic.cpp"

...failed gcc.compile.c++ bin/gcc-7/release/source/test_magic.o...

C++17 example compiler errors (clang-4):

clang-linux.compile.c++.without-pth bin/clang-linux-4.0.0/release/source/test_magic.o
In file included from source/test_magic.cpp:9:
In file included from /home/mike/workspace/magic_get/include/boost/pfr.hpp:12:
In file included from /home/mike/workspace/magic_get/include/boost/pfr/precise.hpp:12:
In file included from /home/mike/workspace/magic_get/include/boost/pfr/precise/core.hpp:20:
In file included from /home/mike/workspace/magic_get/include/boost/pfr/detail/core17.hpp:11:
/home/mike/workspace/magic_get/include/boost/pfr/detail/core17_generated.hpp:51:9: error: cannot decompose this type; 'std::tuple_size<const my_struct>::value' is not a valid integral constant expression
  auto& [a,b] = std::forward<T>(val);
        ^
/home/mike/workspace/magic_get/include/boost/pfr/detail/core17_generated.hpp:1032:30: note: in instantiation of function template specialization 'boost::pfr::detail::as_tuple_impl<const my_struct &>' requested here
  return boost::pfr::detail::as_tuple_impl(val, fields_count_tag{});
                             ^
/home/mike/workspace/magic_get/include/boost/pfr/precise/io.hpp:45:61: note: in instantiation of function template specialization 'boost::pfr::detail::as_tuple<my_struct>' requested here
    detail::print_impl<0, fields_count>::print(out, detail::as_tuple(value));
                                                            ^
/home/mike/workspace/magic_get/include/boost/pfr/precise/ops.hpp:129:21: note: in instantiation of function template specialization 'boost::pfr::write<char, std::char_traits<char>, my_struct>' requested here
        boost::pfr::write(out, value);
                    ^
source/test_magic.cpp:21:24: note: in instantiation of function template specialization 'boost::pfr::ops::operator<<<char, std::char_traits<char>, my_struct>' requested here
        << " fields: " << s << "\n";
                       ^
4 errors generated.

  "clang++" -c -x c++ -march=native -std=c++1z -O3 -Wno-inline -Wall -fPIC  -DBOOST_ALL_DYN_LINK -DNDEBUG -I"/home/mike/workspace/magic_get/include" -I"include" -o "bin/clang-linux-4.0.0/release/source/test_magic.o" "source/test_magic.cpp"

...failed clang-linux.compile.c++.without-pth bin/clang-linux-4.0.0/release/source/test_magic.o...

wrong result for simple example

I used the following code:

#include <iostream>
#include <boost/pfr/precise/tuple_size.hpp>

class Base {
    char a;
    int b;
};

class Derived : Base {
    std::string c;
};

int main() {
    std::cout << boost::pfr::tuple_size<Base>::value << std::endl;
    std::cout << boost::pfr::tuple_size<Derived>::value << std::endl;
}

and I got this as output:

1
1

shouldn't it be 2 and 1?

I'm using these 2 compilers:

  • g++ (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 7.1.0 (under Windows)
  • Microsoft Visual Studio Community 2017 - Version 15.3.1 - VisualStudio.15.Release/15.3.1+26730.8

vs2019 bulid error ..

Visual Studio 2019 (v142)
error C2338: ====================> Boost.PFR: Types with user specified constructors (non-aggregate initializable types) are not supported.
查看对正在编译的函数 模板 实例化“size_t boost::pfr::detail::fields_count(void) noexcept”的引用

struct msg_HelperStr {
HelperStrType _HelperType;
std::string _HelperStr;
};

on vs update after...

struct test{
int a;
int b;
};
std::is_constructible<test,int,int>::value; // value is false ... on Latest vs 2019
so pfr can't work

std::optional in fields

#include <optional>
#include <boost/pfr.hpp>

struct Foo {
    std::optional<int> a;
};

int main() {
    Foo f{5};
    boost::pfr::get<0>(f);
}

Is there any way to compile this code?

I compiled with gcc 6.3 and gcc 7.1 and get the following errors:
error: conversion from 'boost::pfr::detail::loophole_ubiq<Foo, 0>' to 'std::optional<int>' is ambiguous : sequence_tuple::tuple< decltype(T{ loophole_ubiq<T, I>{}... }, 0) > // Instantiating loopholes.

how to get the member name?

I can't find any function to get the member name, i want to use it in my orm framework, is there some way to got it?

C1202 on MSVC, probably on every sizeof(T) >= 256 class

your library is superb! Having that kind of "reflection light" is handy in so many places!

I was going to make an experimental Config class, which can be reflected for Serialization to file or visualisation etc. At some point my MSVC compiler reports error C1202 when trying to call pfr::for_each_field on that class object. After some investigation it seems to appear when the reflected class reaches 256 Bytes. I.e. I can get this error by either adding more members or by increasing the size of each member.

The attached example has 2 defines, if you set one of them, MSVC (VS2017 15.6.2) will emit C1202.
I hope I didn´t make an error, since I´m not sure if my Cfg Templates do actually fit the requirements. I´m afraid its a compiler limitation w/o workarround...
All I can tell is, if it compiles it works as expected. If you are interested to look into this and need more info please let me know. Thanks!

pfr_C1202.zip

Example does not compile VS C++17

The example:

#include <iostream>
#include <string>
#include "boost/pfr/precise.hpp"

struct some_person {
    std::string name;
    unsigned birth_year;
};

int main() {
    some_person val{"Edgar Allan Poe", 1809};

    std::cout << boost::pfr::get<0>(val)                // No macro!
        << " was born in " << boost::pfr::get<1>(val);  // Works with any aggregate initializables!
}

Does not compile:

1>a:\cpp\reftest\reftest\ext\include\boost\pfr\detail\fields_count.hpp(209): error C2338: ====================> Boost.PFR: Types with user specified constructors (non-aggregate initializable types) are not supported.
1>a:\cpp\reftest\reftest\ext\include\boost\pfr\detail\core17_generated.hpp(1036): note: see reference to function template instantiation 'size_t boost::pfr::detail::fields_count<T>(void) noexcept' being compiled
1>        with
1>        [
1>            T=some_person
1>        ]
1>a:\cpp\reftest\reftest\ext\include\boost\pfr\precise\core.hpp(50): note: see reference to function template instantiation 'auto boost::pfr::detail::tie_as_tuple<T>(T &) noexcept' being compiled
1>        with
1>        [
1>            T=some_person
1>        ]
1>a:\cpp\reftest\reftest\src\main.cpp(62): note: see reference to function template instantiation 'decltype(auto) boost::pfr::get<0,some_person>(T &) noexcept' being compiled
1>        with
1>        [
1>            T=some_person
1>        ]
1>a:\cpp\reftest\reftest\ext\include\boost\pfr\detail\fields_count.hpp(214): error C2338: ====================> Boost.PFR: If there's no other failed static asserts then something went wrong. Please report this issue to the github along with the structure you're reflecting.
1>a:\cpp\reftest\reftest\ext\include\boost\pfr\detail\sequence_tuple.hpp(114): error C2338: ====================> Boost.PFR: Tuple index out of bounds
1>a:\cpp\reftest\reftest\ext\include\boost\pfr\precise\core.hpp(50): note: see reference to function template instantiation 'decltype(auto) boost::pfr::detail::sequence_tuple::get<0,>(boost::pfr::detail::sequence_tuple::tuple<> &&) noexcept' being compiled
1>a:\cpp\reftest\reftest\ext\include\boost\pfr\detail\sequence_tuple.hpp(115): error C2672: 'get_impl': no matching overloaded function found
1>a:\cpp\reftest\reftest\ext\include\boost\pfr\detail\sequence_tuple.hpp(113): error C2784: 'T &boost::pfr::detail::sequence_tuple::get_impl(boost::pfr::detail::sequence_tuple::base_from_member<N,T> &) noexcept': could not deduce template argument for 'boost::pfr::detail::sequence_tuple::base_from_member<0,T> &' from 'boost::pfr::detail::sequence_tuple::tuple<>'
1>a:\cpp\reftest\reftest\ext\include\boost\pfr\detail\sequence_tuple.hpp(51): note: see declaration of 'boost::pfr::detail::sequence_tuple::get_impl'
1>a:\cpp\reftest\reftest\src\main.cpp(62): error C2679: binary '<<': no operator found which takes a right-hand operand of type 'void' (or there is no acceptable conversion)

Compiler:

/JMC /permissive- /MP /GS /W3 /Zc:wchar_t /I"A:\cpp\reftest\reftest\ext\include\" /I"A:\cpp\reftest\\include\" /I"C:\Program Files (x86)\Visual Leak Detector\include" /ZI /Gm- /Od /sdl /Fd"x64\Debug\vc141.pdb" /Zc:inline /fp:precise /D "_MBCS" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /MDd /std:c++17 /FC /Fa"x64\Debug\" /EHsc /nologo /Fo"x64\Debug\" /Fp"x64\Debug\reftest.pch" /diagnostics:classic 

`fields_count` seems to not work correctly in C++17 with non-default-constructible types.

A following test case prints 0, rather than 4 in C++17 mode.

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

struct X { X(int) {} };
struct S { X x0; X x1; int x2; X x3; };

int main() {
  std::cout << boost::pfr::detail::fields_count<S>() << '\n';
}

The detect_fields_count case for when initialization fails looks incorrect to me. Specifically, when initialization fails with N arguments, we don't actually know why it failed. It could have failed because (1) too many arguments, or (2) too few arguments. Currently the code assumes that initialization fails due to too many arguments, but as far as I understand default-constructibility is only a requirement in C++14 mode. As such, I believe the code should actually recurse in both directions.

flat_for_each_field not working on MSVC

#include <boost/pfr/flat/core.hpp>

int main() {
    struct nested { int i; short data[3]; };
    struct foo { int i; nested n; };
    std::size_t sum = 0;
    boost::pfr::flat_for_each_field(foo{1, {2, {3, 4, 5}}}, [&sum](auto v) {
        sum += v;
    });
}

This example does not compile, even with /std:c++17 and without /permissive-.

Reproduce: just paste the code in a new console project, set it to c++17 and conformance mode to 'no'

image

This is the error message:

1>    C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.16.27023\bin\HostX86\x64\CL.exe /c /Imagic_get\include /Zi /nologo /W3 /WX- /diagnostics:classic /sdl /O2 /Oi /GL /D NDEBUG /D _CONSOLE /D _UNICODE /D UNICODE /Gm- /EHsc /MD /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /Zc:inline /std:c++17 /Yu"pch.h" /Fp"x64\Release\ConsoleApplication10.pch" /Fo"x64\Release\\" /Fd"x64\Release\vc141.pdb" /Gd /TP /FC /errorReport:prompt ConsoleApplication10.cpp
1>    Tracking command:
1>    C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\Tracker.exe /d "C:\Program Files (x86)\MSBuild\15.0\FileTracker\FileTracker32.dll" /i "C:\Users\Jan Wilmans\source\repos\ConsoleApplication10\ConsoleApplication10\x64\Release\ConsoleA.D2A74CDF.tlog" /r "C:\USERS\JAN WILMANS\SOURCE\REPOS\CONSOLEAPPLICATION10\CONSOLEAPPLICATION10\CONSOLEAPPLICATION10.CPP" /b MSBuildConsole_CancelEvent3fe69d296dda41e989270a8edadfde3e  /c "C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.16.27023\bin\HostX86\x64\CL.exe"  /c /Imagic_get\include /Zi /nologo /W3 /WX- /diagnostics:classic /sdl /O2 /Oi /GL /D NDEBUG /D _CONSOLE /D _UNICODE /D UNICODE /Gm- /EHsc /MD /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /Zc:inline /std:c++17 /Yu"pch.h" /Fp"x64\Release\ConsoleApplication10.pch" /Fo"x64\Release\\" /Fd"x64\Release\vc141.pdb" /Gd /TP /FC /errorReport:prompt ConsoleApplication10.cpp
1>    ConsoleApplication10.cpp
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(103): error C3779: 'boost::pfr::detail::loophole': a function that returns 'auto' cannot be used before it is defined
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(59): note: see declaration of 'boost::pfr::detail::loophole'
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(162): note: see reference to class template instantiation 'boost::pfr::detail::loophole_type_list_lref<T,U>' being compiled
1>            with
1>            [
1>                T=type,
1>                U=indexes
1>            ]
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(237): note: see reference to function template instantiation 'auto boost::pfr::detail::tie_as_tuple_loophole_impl<T>(T &) noexcept' being compiled
1>            with
1>            [
1>                T=main::foo
1>            ]
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\flat\core.hpp(133): note: see reference to function template instantiation 'auto boost::pfr::detail::tie_as_flat_tuple<T>(T &)' being compiled
1>            with
1>            [
1>                T=main::foo
1>            ]
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\consoleapplication10.cpp(11): note: see reference to function template instantiation 'void boost::pfr::flat_for_each_field<main::foo,main::<lambda_611397c7fcdc2babe31551a0ec0cc907>>(T &&,F &&)' being compiled
1>            with
1>            [
1>                T=main::foo,
1>                F=main::<lambda_611397c7fcdc2babe31551a0ec0cc907>
1>            ]
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(128): error C3779: 'boost::pfr::detail::loophole': a function that returns 'auto' cannot be used before it is defined
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(59): note: see declaration of 'boost::pfr::detail::loophole'
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(166): error C3203: 'tuple': unspecialized class template can't be used as a template argument for template parameter 'S', expected a real type
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\offset_based_getter.hpp(63): error C2338: ====================> Boost.PFR: Member sequence does not indicate correct size for struct type!
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(166): note: see reference to class template instantiation 'boost::pfr::detail::offset_based_getter<type,int>' being compiled
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(168): error C2955: 'boost::pfr::detail::sequence_tuple::tuple': use of class template requires template argument list
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\sequence_tuple.hpp(78): note: see declaration of 'boost::pfr::detail::sequence_tuple::tuple'
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(168): error C2512: 'std::integral_constant<size_t,Index>': no appropriate default constructor available
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(168): note: The target type has no constructors
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(164): error C2672: 'boost::pfr::detail::make_flat_tuple_of_references': no matching overloaded function found
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(169): error C2780: 'auto boost::pfr::detail::make_flat_tuple_of_references(TupleOrUserType &,const Getter &,std::integral_constant<size_t,Index>,std::integral_constant<size_t,1>) noexcept': expects 4 arguments - 3 provided
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\make_flat_tuple_of_references.hpp(40): note: see declaration of 'boost::pfr::detail::make_flat_tuple_of_references'
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(169): error C2780: 'boost::pfr::detail::sequence_tuple::tuple<> boost::pfr::detail::make_flat_tuple_of_references(TupleOrUserType &,const Getter &,std::integral_constant<size_t,Index>,std::integral_constant<size_t,0>) noexcept': expects 4 arguments - 3 provided
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\make_flat_tuple_of_references.hpp(37): note: see declaration of 'boost::pfr::detail::make_flat_tuple_of_references'
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(169): error C2780: 'auto boost::pfr::detail::make_flat_tuple_of_references(TupleOrUserType &,const Getter &,std::integral_constant<size_t,Index>,std::integral_constant<size_t,Index>) noexcept': expects 4 arguments - 3 provided
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\make_flat_tuple_of_references.hpp(34): note: see declaration of 'boost::pfr::detail::make_flat_tuple_of_references'
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(236): error C2672: 'boost::pfr::detail::tie_as_tuple_recursively': no matching overloaded function found
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(238): error C2893: Failed to specialize function template 'auto boost::pfr::detail::tie_as_tuple_recursively(T &&) noexcept'
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(238): note: With the following template arguments:
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(238): note: 'T=void'
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(241): error C3536: 'rec_tuples': cannot be used before it is initialized
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(241): error C2651: 'int': left of '::' must be a class, struct or union
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(241): error C2062: type 'unknown-type' unexpected
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(241): error C2039: 'size_v': is not a member of '`global namespace''
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(241): error C2143: syntax error: missing ';' before '{'
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(242): error C2059: syntax error: ')'
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\flat\core.hpp(133): error C3313: 'tup': variable cannot have the type 'void'
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\flat\core.hpp(135): error C3536: 'tup': cannot be used before it is initialized
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\flat\tuple_size.hpp(26): error C2651: 'void': left of '::' must be a class, struct or union
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\flat\tuple_size.hpp(36): note: see reference to alias template instantiation 'boost::pfr::flat_tuple_size<main::foo>' being compiled
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\flat\core.hpp(137): note: see reference to variable template 'const size_t flat_tuple_size_v<`main'::`2'::foo>' being compiled
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\flat\tuple_size.hpp(26): error C2062: type 'unknown-type' unexpected
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\flat\tuple_size.hpp(26): error C2039: 'size_v': is not a member of '`global namespace''
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\flat\tuple_size.hpp(36): error C2938: 'boost::pfr::flat_tuple_size<main::foo>' : Failed to specialize alias template
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\flat\tuple_size.hpp(36): error C2062: type 'unknown-type' unexpected
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\flat\tuple_size.hpp(36): error C2039: 'value': is not a member of '`global namespace''
1>    c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\flat\core.hpp(137): error C3376: 'boost::pfr::flat_tuple_size_v': only static data member templates are allowed
1>    The command exited with code 2.
1>  Done executing task "CL" -- FAILED.
1>Done building target "ClCompile" in project "ConsoleApplication10.vcxproj" -- FAILED.
1>
1>Done building project "ConsoleApplication10.vcxproj" -- FAILED.
1>
1>Build FAILED.
1>
1>c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(103): error C3779: 'boost::pfr::detail::loophole': a function that returns 'auto' cannot be used before it is defined
1>c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(128): error C3779: 'boost::pfr::detail::loophole': a function that returns 'auto' cannot be used before it is defined
1>c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(166): error C3203: 'tuple': unspecialized class template can't be used as a template argument for template parameter 'S', expected a real type
1>c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\offset_based_getter.hpp(63): error C2338: ====================> Boost.PFR: Member sequence does not indicate correct size for struct type!
1>c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(168): error C2955: 'boost::pfr::detail::sequence_tuple::tuple': use of class template requires template argument list
1>c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(168): error C2512: 'std::integral_constant<size_t,Index>': no appropriate default constructor available
1>c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(164): error C2672: 'boost::pfr::detail::make_flat_tuple_of_references': no matching overloaded function found
1>c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(169): error C2780: 'auto boost::pfr::detail::make_flat_tuple_of_references(TupleOrUserType &,const Getter &,std::integral_constant<size_t,Index>,std::integral_constant<size_t,1>) noexcept': expects 4 arguments - 3 provided
1>c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(169): error C2780: 'boost::pfr::detail::sequence_tuple::tuple<> boost::pfr::detail::make_flat_tuple_of_references(TupleOrUserType &,const Getter &,std::integral_constant<size_t,Index>,std::integral_constant<size_t,0>) noexcept': expects 4 arguments - 3 provided
1>c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(169): error C2780: 'auto boost::pfr::detail::make_flat_tuple_of_references(TupleOrUserType &,const Getter &,std::integral_constant<size_t,Index>,std::integral_constant<size_t,Index>) noexcept': expects 4 arguments - 3 provided
1>c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(236): error C2672: 'boost::pfr::detail::tie_as_tuple_recursively': no matching overloaded function found
1>c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(238): error C2893: Failed to specialize function template 'auto boost::pfr::detail::tie_as_tuple_recursively(T &&) noexcept'
1>c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(241): error C3536: 'rec_tuples': cannot be used before it is initialized
1>c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(241): error C2651: 'int': left of '::' must be a class, struct or union
1>c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(241): error C2062: type 'unknown-type' unexpected
1>c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(241): error C2039: 'size_v': is not a member of '`global namespace''
1>c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(241): error C2143: syntax error: missing ';' before '{'
1>c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\detail\core14_loophole.hpp(242): error C2059: syntax error: ')'
1>c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\flat\core.hpp(133): error C3313: 'tup': variable cannot have the type 'void'
1>c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\flat\core.hpp(135): error C3536: 'tup': cannot be used before it is initialized
1>c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\flat\tuple_size.hpp(26): error C2651: 'void': left of '::' must be a class, struct or union
1>c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\flat\tuple_size.hpp(26): error C2062: type 'unknown-type' unexpected
1>c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\flat\tuple_size.hpp(26): error C2039: 'size_v': is not a member of '`global namespace''
1>c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\flat\tuple_size.hpp(36): error C2938: 'boost::pfr::flat_tuple_size<main::foo>' : Failed to specialize alias template
1>c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\flat\tuple_size.hpp(36): error C2062: type 'unknown-type' unexpected
1>c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\flat\tuple_size.hpp(36): error C2039: 'value': is not a member of '`global namespace''
1>c:\users\jan wilmans\source\repos\consoleapplication10\consoleapplication10\magic_get\include\boost\pfr\flat\core.hpp(137): error C3376: 'boost::pfr::flat_tuple_size_v': only static data member templates are allowed
1>    0 Warning(s)
1>    27 Error(s)
1>
1>Time Elapsed 00:00:00.52
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Errors for classes with empty base(s), C++17

Provided the following hierarchy of classes:

namespace empty_base {

struct A {};
struct B {};

// Empty base, no members
struct C : A {};
// Empty base, some members
struct D : A { double d; };
// Two empty bases, no members
struct E : A, B {};
// Two empty bases, some membes
struct F : A, B { float f; };

}

When trying to use pfr with them there are the following errors (the error messages are somewhat shortened):

Class with an empty base and no members
Precise:

> decltype(structure_to_tuple(declval<empty_base::C>()))
./include/boost/pfr/detail/core17_generated.hpp:39:9: fatal error: type 'const empty_base::C' decomposes into 0 elements, but 1 names were provided
  auto& [a] = val;
        ^
./include/boost/pfr/detail/core17_generated.hpp:1037:30: note: in instantiation of function template specialization 'boost::pfr::detail::tie_as_tuple<const empty_base::C>' requested here
  return boost::pfr::detail::tie_as_tuple(val, fields_count_tag{});
                             ^
./include/boost/pfr/precise/core.hpp:93:17: note: in instantiation of function template specialization 'boost::pfr::detail::tie_as_tuple<const empty_base::C>' requested here
        detail::tie_as_tuple(val),

Flat:

> decltype(flat_structure_to_tuple(declval<empty_base::C>()))
std::tuple<> // This is fine, actually

Class with an empty base and some members
Presize:

> decltype(structure_to_tuple(declval<empty_base::D>()))
./include/boost/pfr/detail/core17_generated.hpp:52:9: fatal error: type 'const empty_base::D' decomposes into 1 elements, but 2 names were provided
  auto& [a,b] = val;
        ^
./include/boost/pfr/detail/core17_generated.hpp:1037:30: note: in instantiation of function template specialization 'boost::pfr::detail::tie_as_tuple<const empty_base::D>' requested here
  return boost::pfr::detail::tie_as_tuple(val, fields_count_tag{});
                             ^
./include/boost/pfr/precise/core.hpp:93:17: note: in instantiation of function template specialization 'boost::pfr::detail::tie_as_tuple<const empty_base::D>' requested here
        detail::tie_as_tuple(val)

Flat:

> decltype(flat_structure_to_tuple(declval<empty_base::D>()))
./include/boost/pfr/detail/offset_based_getter.hpp:63:3: fatal error: static_assert failed "====================> Boost.PFR: Member sequence does not indicate correct size for struct type!"
  static_assert(sizeof(U) == sizeof(S), "====================> Boost.PFR: Member sequence does not indicate correct size for struct type!");
// Nice assert, but doesn't help, actually

Class with two empty bases and no members
Precise:

> decltype(structure_to_tuple(declval<empty_base::E>()))
./include/boost/pfr/detail/core17_generated.hpp:52:9: fatal error: type 'const empty_base::E' decomposes into 0 elements, but 2 names were provided
  auto& [a,b] = val;

Flat:

> decltype(flat_structure_to_tuple(declval<empty_base::E>()))
./include/boost/pfr/detail/offset_based_getter.hpp:63:3: fatal error: static_assert failed "====================> Boost.PFR: Member sequence does not indicate correct size for struct type!"
  static_assert(sizeof(U) == sizeof(S), "====================> Boost.PFR: Member sequence does not indicate correct size for struct type!");

Class with two empty bases and some members
Precise:

> decltype(structure_to_tuple(declval<empty_base::F>()))
./include/boost/pfr/detail/core17_generated.hpp:58:9: fatal error: type 'const empty_base::F' decomposes into 1 elements, but 3 names were provided
  auto& [a,b,c] = val;

Flat:

> decltype(flat_structure_to_tuple(declval<empty_base::F>()))
./include/boost/pfr/detail/offset_based_getter.hpp:63:3: fatal error: static_assert failed "====================> Boost.PFR: Member sequence does not indicate correct size for struct type!"
  static_assert(sizeof(U) == sizeof(S), "====================> Boost.PFR: Member sequence does not indicate correct size for struct type!");

Manual type registering/structured bindings might be unnecessary

It occurred to me that it is possible to implement as_tuple in C++14 very easily using the visitor pattern, with the added benefit of supporting pointers, enums and non primitive types out of the box.

Following is a rough implementation of the idea, which outputs:

{42, a, 3.1, (nil), green, hello world!}

for

as_tuple(reg{42, 'a', 3.1, nullptr, color::green, "hello world!"}, [](auto&& t) {
    print_tuple(std::forward<decltype(t)>(t));
    std::cout << std::endl;
});

where

struct reg {
    int a;
    char b;
    double d;
    void* e;
    color f;
    std::string g;
};

and

enum class color {
    red,
    green,
    blue
};

std::ostream& operator <<(std::ostream& os, color c) {
    switch(c) {
        case color::red:
            os << "red";
            break;
        case color::green:
            os << "green";
            break;
        case color::blue:
            os << "blue";
            break;
    };

    return os;
}

Note: it only works on Clang + libc++ due to the reinterpret_cast to std::tuple.

#include <tuple>
#include <cstdint>
#include <utility>
#include <iostream>
#include <type_traits>
#include <initializer_list>

template<typename...>
using void_t = void;

template<typename>
struct type {};

template<std::size_t>
struct ubiq
{
    template<typename T>
    operator T() const;
};


template<typename, typename, typename = void>
struct _size_impl
{};

template<typename T, std::size_t head, std::size_t... tail>
struct _size_impl<T, std::index_sequence<head, tail...>,
    void_t<decltype(T{ubiq<head>{}, ubiq<tail>{}...})>
> :
    std::integral_constant<std::size_t, sizeof...(tail) + 1>
{};

template<typename T, std::size_t head, std::size_t... tail, typename _>
struct _size_impl<T, std::index_sequence<head, tail...>, _> :
    _size_impl<T, std::index_sequence<tail...>>
{};

template<typename T>
struct _size :
    _size_impl<T, std::make_index_sequence<sizeof(T)>>
{};

template<typename T>
using size = typename _size<T>::type;

template<typename F>
struct deducer
{
    F f;

    template<typename T>
    operator T() const {
        f(type<T>{});
        return {};
    }
};

template<typename F>
deducer<std::decay_t<F>> deduce(F&& f) {
    return {std::forward<F>(f)};
}

template<typename F, typename T, typename... Props>
auto as_tuple_impl(F&& f, T&& t, type<Props>...)
    -> std::enable_if_t<size<std::decay_t<T>>::value != sizeof...(Props)> {
    std::decay_t<T>{
        Props{}...,
        deduce(
            [&f, &t](auto prop) {
                as_tuple_impl(
                    std::forward<F>(f),
                    std::forward<T>(t),
                    type<Props>{}...,
                    prop
                );
            }
        )
    };
}

template<typename F, typename T, typename... Props>
auto as_tuple_impl(F&& f, T&& t, type<Props>...)
    -> std::enable_if_t<size<std::decay_t<T>>::value == sizeof...(Props)> {
    std::forward<F>(f)(reinterpret_cast<std::tuple<Props...>&&>(t));
}

template<typename F, typename T, typename... Props>
auto as_tuple_impl(F&& f, T& t, type<Props>...)
    -> std::enable_if_t<size<T>::value == sizeof...(Props)> {
    std::forward<F>(f)(reinterpret_cast<std::tuple<Props...>&>(t));
}

template<typename T, typename F>
auto as_tuple(T&& t, F&& f) {
    as_tuple_impl(std::forward<F>(f), std::forward<T>(t));
}

template<typename... R, std::size_t h, std::size_t... t>
void print_tuple_impl(std::tuple<R...> const& r, std::index_sequence<h, t...>) {
    std::cout << '{' << std::get<h>(r);
    std::initializer_list<int>{
        (void(std::cout << ", " << std::get<t>(r)), 0)...
    };
    std::cout << '}';
}

template<typename... T>
void print_tuple(std::tuple<T...> const& t) {
    print_tuple_impl(t, std::index_sequence_for<T...>{});
}

Improve instructions for regenerating core17_generated.hpp

The instructions on how to regenerate file include/boost/pfr/detail/core17_generated.hpp located at https://github.com/boostorg/pfr/blob/develop/misc/generate_cpp17.py#L70 say:

`python ./misc/generate_cpp17.py 300 > include/boost/pfr/detail/core17_generated.hpp`

The script is written in python2 and when I invoke this command on my default python -- which is version 3 -- I get syntax errors (print requires parentheses).

I think you either need to rewrite the script to be python3, or change the instructions to invoke python2, or some combination of both of these.

Some tests are not running in CI on Appveyor (MSVC)

Not all tests from /test/flat are appearently running on the appveyor CI.
from all the tests below, I see only 1 running / being compiled er in the logs.

core.cpp
destructuring_tie.cpp  // this is the only test that I see running in the log file on appveyor 
flat_for_each_field.cpp
flat_motivating_example.cpp
flat_motivating_example2.cpp
flat_tuple_size.cpp
flat_tuple_size_on_bitfields.cpp
flat_tuple_size_on_non_aggregate.cpp

Reopen #27

Issue #27 should have been fixed in latest master but it doesn't.

Compiling

#include <memory>
#include <boost/pfr.hpp>

struct Message {
  std::unique_ptr<int> data;
};

int main(int argc, char* argv[]) {
  Message message;
  auto& ptr = boost::pfr::get<0>(message);
  return 0;
}

gives me

In file included from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14.hpp:13:0,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/precise/core.hpp:23,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/precise.hpp:12,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr.hpp:12,
                 from /tmp/untitled/main.cpp:2:
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14_loophole.hpp: In instantiation of ‘struct boost::pfr::detail::loophole_type_list<Message, std::integer_sequence<unsigned int, 0u> >’:
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14_loophole.hpp:108:72:   required from ‘auto boost::pfr::detail::tie_as_tuple_loophole_impl(T&) [with T = Message]’
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14_loophole.hpp:199:58:   required from ‘auto boost::pfr::detail::tie_as_tuple(T&) [with T = Message]’
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/precise/core.hpp:50:64:   required from ‘constexpr decltype(auto) boost::pfr::get(T&) [with unsigned int I = 0u; T = Message]’
/tmp/untitled/main.cpp:10:41:   required from here
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14_loophole.hpp:98:68: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]’
     : sequence_tuple::tuple< decltype(T{ loophole_ubiq<T, I>{}... }, 0) >
                                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~
In file included from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/c++/6.3.0/memory:81:0,
                 from /tmp/untitled/main.cpp:1:
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/c++/6.3.0/bits/unique_ptr.h:359:7: note: declared here
       unique_ptr(const unique_ptr&) = delete;
       ^~~~~~~~~~
In file included from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14.hpp:13:0,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/precise/core.hpp:23,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/precise.hpp:12,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr.hpp:12,
                 from /tmp/untitled/main.cpp:2:
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14_loophole.hpp:87:15: note:   after user-defined conversion: constexpr boost::pfr::detail::loophole_ubiq<T, N>::operator U&() const [with U = std::unique_ptr<int>; unsigned int <anonymous> = 1u; T = Message; unsigned int N = 0u]
     constexpr operator U&() const noexcept; // `const` here helps to avoid ambiguity in loophole instantiations. optional_like test validate that behavior.
               ^~~~~~~~
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14_loophole.hpp:100:58: error: use of ‘auto boost::pfr::detail::loophole(boost::pfr::detail::tag<Message, 0u>)’ before deduction of ‘auto’
     using type = sequence_tuple::tuple< decltype(loophole(tag<T, I>{}))... >;
                                                  ~~~~~~~~^~~~~~~~~~~~~
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14_loophole.hpp:100:58: error: use of ‘auto boost::pfr::detail::loophole(boost::pfr::detail::tag<Message, 0u>)’ before deduction of ‘auto’
In file included from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/precise.hpp:12:0,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr.hpp:12,
                 from /tmp/untitled/main.cpp:2:
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/precise/core.hpp: In instantiation of ‘constexpr decltype(auto) boost::pfr::get(T&) [with unsigned int I = 0u; T = Message]’:
/tmp/untitled/main.cpp:10:41:   required from here
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/precise/core.hpp:50:42: error: invalid use of void expression
     return detail::sequence_tuple::get<I>( detail::tie_as_tuple(val) );
            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/tmp/untitled/main.cpp: In function ‘int main(int, char**)’:
/tmp/untitled/main.cpp:10:41: error: forming reference to void
   auto& ptr = boost::pfr::get<0>(message);
                                         ^
make[2]: *** [CMakeFiles/untitled.dir/main.cpp.o] Error 1
make[1]: *** [CMakeFiles/untitled.dir/all] Error 2

Reflecting array members of aggregate structs

Reflection of member array types is possible by refining magic_get methods.

Recursive scheme

Here's a scheme for finding an aggregate's member types one at a time:

Given an aggregate-initializable struct S:

  1. Assume initial member types T... of S are known (none to start)
    => S can be aggregate initialized as S { T_init... }
    with T_init braced or unbraced initialization as needed by T
    (scalars need unbraced init, arrays need braced init => awkward).
  2. Attempt aggregate initialization S { T_init..., ubiq_init }
    where ubiq is the usual convert-to-anything type.
    If this fails then T... is the complete list of members: Done.
  3. Else redo initialization (2) but capture the ubiq converted-to type L
    (either by 'Great Type Loophole' or by typeid memo).
    If the member is array type then L is its base type
    (on gcc ubiq actually sees the full array type - a tempting anomaly)
  4. Introspect the rank of the member base type L found in (3):
    Attempt initializations of S { T_init..., {L_init} }
    with increasing depth of nested braces => deduce the rank
  5. For non-zero rank, i.e. array types, find the array bounds:
    e.g. for an array of rank 2 attempt initializations
    S { T_init..., {{Li...}} }
    S { T_init..., {{Li}...} }
    with increasing numbers Li... => the maxes are the array bounds
  6. Append the new type to the known initiial member types T...
  7. Goto (1)
  • This scheme is not fully generic because of the need for both
    braced and unbraced init syntax in the comma-separated init list
    (variadic expansion of differing syntax in that context seems impossible).
  • Also, array rank deduction has an implementation-defined depth limit.

Array vs Scalar init

Arrays and scalar types don't mix well in braced-init lists, requiring non-uniform initialization;
to support both requires expanding both braced and unbraced initialization syntax.
Again, given aggregate-initializable struct S with known initial member type sequence T...

  • Expanding unbraced S{ T{}... } fails for T = L[N] array type
    • array must be initialized with a brace-enclosed initializer.
  • Expanding braced S{ {T{}}... } fails for scalar
    • error: braces around scalar initializer

A 'Catch 22' situation in generating a suitable init-list:

Workarounds for non-uniform initialization syntax

For the initial member type initializations:

  • Separate T... into runs requiring braced or unbraced initialization:
  • Support pairs of unbraced runs Ui and braced runs Bi to some limit N:
    • T... -> Ts<U0....>, Ts<B0....> ... Ts<UN-1...>, Ts<BN-1...>

A different workaround would be to flatten all arrays and do all unbraced inits.
For large arrays this explodes compile time and memory usage.
Or, for a mixed workaround, fallback to flattening arrays only when necessary.
If more than N pairs of runs are needed, selectively flatten smaller arrays
in order to remove braced runs until there are only N pairs of runs.

Proof of Concept code

I have code for this scheme, done in C++17 plus -fconcepts for ease
(so currently limited to gcc, but not using gcc's direct extraction of the array type).
It is prototype / experimental code that has not been much exercised yet.
It is around 500 LOC including comments.
It uses the Loophole ubiq.
It expands up to 4 array dimensions.
It expands up to 4 pairs of unbraced,braced runs
(the array-flattening fallback has not been implemented so 4 is a hard limit).
In principle, it should be possible to backport to C++14.
I'm not motivated to backport or test with Clang / MSVC until they have concepts.
Compile time for large arrays gets noticeable, likely the binary search for bounds.

Contribute to pfr / magic_get?

I'm happy to provide the code in current form, to see if it is suitable for inclusion.
There seem to be more cons than pros though...

Cons:
Arrays are awkward types so still need special-casing in generic client code.
Don't want to encourage C-array usage - std::array is better if it can be used.
Consumes more compile resource than current 'precise' and 'flat' methods.
It comes burdened with implementation-defined limits.
The code is involved so there's a maintenance cost.
The backport is not trivial.

Pros:
Its the only way I know to reflect array members.
Because it's there.

Note on structured bindings and 'structured reflection'

Structured bindings get tantalisingly close to complete 'precise' struct reflection;
if you know the member count in a struct then you can bind to and get all types.
If you don't know then you have to count, but you can't directly count because
you can't SFINAE on a structured binding failing, so you have to count indirectly.
For an aggregate, this means counting via the init-list. We're back to init, innit.
Egg-bound by the chickens.

I floated this template-matching syntax for 'structured reflection';

template <class A> struct destructure;

template <class A, auto... mp>
struct destructure<A::[mp...]> {
     using member_pointers = Members<mp...>;
};

struct S { bool b; char c[4]; };
using S_members = typename destructure<S>::member_pointers;

If only it were this simple.

Support std::optional<>

It seems that std::experimental::optional (c++14) or std::optional(c++17) are not supported

n file included from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14_loophole.hpp:29:0,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14.hpp:13,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/precise/core.hpp:24,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/precise.hpp:12,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr.hpp:12,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/LibVimarIPCParser/BaseValueHandlers.h:6,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/LibVimarIPCParser/StdValueHandlers.h:4,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/LibVimarIPCParser/UserParser.h:4,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/LibVimarIPCParser/SystemFunctionParser.h:10,
                 from /home/cucchetf/workspace/p378_ipconnectorserver/src/ipc/SFClientIPC.h:5,
                 from /home/cucchetf/workspace/p378_ipconnectorserver/src/ipc/SFClientIPC.cpp:1:
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/offset_based_getter.hpp: In instantiation of ‘class boost::pfr::detail::offset_based_getter<ipconnector::Temp, boost::pfr::detail::sequence_tuple::tuple<int, int> >’:
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14_loophole.hpp:154:61:   required from ‘auto boost::pfr::detail::tie_as_tuple_loophole_impl(T&) [with T = ipconnector::Temp]’
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14_loophole.hpp:255:55:   required from ‘void boost::pfr::detail::for_each_field_dispatcher(T&, F&&, std::index_sequence<I ...>) [with T = ipconnector::Temp; F = boost::pfr::for_each_field(T&&, F&&) [with T = ipconnector::Temp&; F = ipconnector::SFClientIPC::ModifyScene(const VimarIPCParser::SystemFunctionParser::ModifySceneRequest&)::<lambda(const auto:9&)>]::<lambda(auto:1&&)>; unsigned int ...I = {0u, 1u}; std::index_sequence<I ...> = std::integer_sequence<unsigned int, 0u, 1u>]’
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/precise/core.hpp:140:52:   required from ‘void boost::pfr::for_each_field(T&&, F&&) [with T = ipconnector::Temp&; F = ipconnector::SFClientIPC::ModifyScene(const VimarIPCParser::SystemFunctionParser::ModifySceneRequest&)::<lambda(const auto:9&)>]’
/home/cucchetf/workspace/p378_ipconnectorserver/src/ipc/SFClientIPC.cpp:117:56:   required from here
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/offset_based_getter.hpp:63:3: error: static assertion failed: ====================> Boost.PFR: Member sequence does not indicate correct size for struct type!
   static_assert(sizeof(U) == sizeof(S), "====================> Boost.PFR: Member sequence does not indicate correct size for struct type!");
   ^~~~~~~~~~~~~
In file included from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14.hpp:13:0,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/precise/core.hpp:24,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/precise.hpp:12,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr.hpp:12,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/LibVimarIPCParser/BaseValueHandlers.h:6,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/LibVimarIPCParser/StdValueHandlers.h:4,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/LibVimarIPCParser/UserParser.h:4,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/LibVimarIPCParser/SystemFunctionParser.h:10,
                 from /home/cucchetf/workspace/p378_ipconnectorserver/src/ipc/SFClientIPC.h:5,
                 from /home/cucchetf/workspace/p378_ipconnectorserver/src/ipc/SFClientIPC.cpp:1:
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14_loophole.hpp: In instantiation of ‘void boost::pfr::detail::for_each_field_dispatcher(T&, F&&, std::index_sequence<I ...>) [with T = ipconnector::Temp; F = boost::pfr::for_each_field(T&&, F&&) [with T = ipconnector::Temp&; F = ipconnector::SFClientIPC::ModifyScene(const VimarIPCParser::SystemFunctionParser::ModifySceneRequest&)::<lambda(const auto:9&)>]::<lambda(auto:1&&)>; unsigned int ...I = {0u, 1u}; std::index_sequence<I ...> = std::integer_sequence<unsigned int, 0u, 1u>]’:
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/precise/core.hpp:140:52:   required from ‘void boost::pfr::for_each_field(T&&, F&&) [with T = ipconnector::Temp&; F = ipconnector::SFClientIPC::ModifyScene(const VimarIPCParser::SystemFunctionParser::ModifySceneRequest&)::<lambda(const auto:9&)>]’
/home/cucchetf/workspace/p378_ipconnectorserver/src/ipc/SFClientIPC.cpp:117:56:   required from here
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14_loophole.hpp:254:23: error: use of ‘boost::pfr::for_each_field(T&&, F&&)::<lambda(auto:1&&)> mutable [with auto:1 = boost::pfr::detail::sequence_tuple::tuple<int&, int&>; T = ipconnector::Temp&; F = ipconnector::SFClientIPC::ModifyScene(const VimarIPCParser::SystemFunctionParser::ModifySceneRequest&)::<lambda(const auto:9&)>]’ before deduction of ‘auto’
     std::forward<F>(f)(
     ~~~~~~~~~~~~~~~~~~^
         boost::pfr::detail::tie_as_tuple_loophole_impl(t)
         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     );
     ~                  

want to add `pointers to data members -> index`

template<class T>
struct DelayConstruct {
	static inline T value{};  // construct in runtime.  
};
template<class T, class M>
constexpr std::size_t get_index(M T::*mem_ptr) {
	auto &t = DelayConstruct<T>::value;
	return
		std::apply([&](auto&...e) {
			int idx = 0;
			std::array<void*, sizeof...(e)> list = { (void*)&e ... };
			for (auto b : list) {
				if (b == &(t.*mem_ptr))
					return idx;
				idx += 1;
			}
			return 42;
		}, structure_tie(t));
}
//example1
struct S {
	std::string x;
	std::vector<int> y;
	std::string z;
};

static_assert(boost::pfr::get_index(&S::x) == 0);
static_assert(boost::pfr::get_index(&S::y) == 1);
static_assert(boost::pfr::get_index(&S::z) == 2);
//example2
struct S {
	static constexpr auto names = std::make_tuple("x","y","z");
	std::string x;
	std::vector<int> y;
	std::string z;
};

assert(std::string_view{"x"} == std::get<boost::pfr::get_index(&S::x)>(S::names));
assert(std::string_view{"y"} == std::get<boost::pfr::get_index(&S::y)>(S::names));
assert(std::string_view{"z"} == std::get<boost::pfr::get_index(&S::z)>(S::names));

Investigate and report ICE

test-2 and test-3:
https://github.com/madmongo1/pfr_review/blob/master/pre-cxx20/test-2.cpp
Seems to produce infinite recursive template expansion

The example should not compile, because the nested types are not aggregates.

In C++14 it gives a correct static assert

../../../boost/pfr/detail/core14_classic.hpp:509:5: error:
static_assert failed "====================> Boost.PFR: Type can not be
used is flat_ functions, because it's not POD"

in C++17 it also gives a correct static assert

../../../boost/pfr/detail/fields_count.hpp:225:9: error: static
assertion failed: ====================> Boost.PFR: Type must be
aggregate initializable.

Clang crashes after that.
GCC goes into an infinite loop, ignoring all the template
instantiation depth limitations and static_assert messages printing.

Using BOOST_PFR_PRECISE_FUNCTIONS_FOR now gives a complaint of missing
sd::hash specialization:

../../../boost/pfr/detail/functional.hpp:133:9: error: static_assert
failed due to requirement 'sizeof(boost::basic_string_view<char,
std::char_traits >) && false' "====================> Boost.PFR:
std::hash not specialized for type T"

I've added the tests and will report issues to the compiler developers soon.

pfr::ops doesn't support unions in PODs

First off, I love this library. I find myself writing a lot of binary protocols that support unions. One thing I do to test out my binary parsers/generators, is just sending the instance to operator<< and not having to write a 100+ line function myself, I love this (ehm, Rust has this as well).

Any ideas on how you could support unions? Maybe just convert to std::tuple<> and print that? I've gotten boost::hana to play nice sometimes but nothing notable. I think if you support unions, lots of C code or legacy C++ could be brought to a new light by just automatically having pfr::ops work.

Thanks!

Invalid struct size with tuple with one type not trivial

Hi,
this works

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

using namespace std;

struct Message {
  std::tuple<int, std::string> temp;
};


int main() {
  Message msg;
  boost::pfr::for_each_field(msg, [](const auto & field) {});
  return 0;
}

and this one too

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

using namespace std;

struct Message {
  std::tuple<std::string, int> temp;
};


int main() {
  Message msg;
  boost::pfr::for_each_field(msg, [](const auto & field) {});
  return 0;
}

and also this

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

using namespace std;

struct Message {
  std::tuple<int> temp;
};


int main() {
  Message msg;
  boost::pfr::for_each_field(msg, [](const auto & field) {});
  return 0;
}

but this one NO!!

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

using namespace std;

struct Message {
  std::tuple<std::string> temp;
};


int main() {
  Message msg;
  boost::pfr::for_each_field(msg, [](const auto & field) {});
  return 0;
}

This is the output

18:02:47: Running steps for project untitled...
18:02:47: Starting: "/home/cucchetf/tools/cmake/bin/cmake" --build . --target all
[1/2 0.5/sec] Building CXX object CMakeFiles/untitled.dir/main.cpp.o
FAILED: CMakeFiles/untitled.dir/main.cpp.o 
distcc /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi-g++ --sysroot=/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi    -march=armv7-a -marm -mfpu=neon  -mfloat-abi=hard -mcpu=cortex-a9 -g -MD -MT CMakeFiles/untitled.dir/main.cpp.o -MF CMakeFiles/untitled.dir/main.cpp.o.d -o CMakeFiles/untitled.dir/main.cpp.o -c /tmp/untitled/main.cpp
distcc[16882] Warning: INCLUDE_SERVER_PORT not set - did you forget to run under 'distcc-pump'?
distcc[16882] (dcc_build_somewhere) Warning: failed to get includes from include server, preprocessing locally
distcc[16882] ERROR: compile /tmp/untitled/main.cpp on 127.0.0.1,lzo,cpp failed
distcc[16882] (dcc_build_somewhere) Warning: remote compilation of '/tmp/untitled/main.cpp' failed, retrying locally
distcc[16882] Warning: failed to distribute /tmp/untitled/main.cpp to 127.0.0.1,lzo,cpp, running locally instead
In file included from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14_loophole.hpp:29:0,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14.hpp:13,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/precise/core.hpp:24,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/precise.hpp:12,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr.hpp:12,
                 from /tmp/untitled/main.cpp:2:
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/offset_based_getter.hpp: In instantiation of ‘class boost::pfr::detail::offset_based_getter<Message, boost::pfr::detail::sequence_tuple::tuple<std::allocator<char> > >’:
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14_loophole.hpp:154:61:   required from ‘auto boost::pfr::detail::tie_as_tuple_loophole_impl(T&) [with T = Message]’
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14_loophole.hpp:255:55:   required from ‘void boost::pfr::detail::for_each_field_dispatcher(T&, F&&, std::index_sequence<I ...>) [with T = Message; F = boost::pfr::for_each_field(T&&, F&&) [with T = Message&; F = main()::<lambda(const auto:7&)>]::<lambda(auto:1&&)>; unsigned int ...I = {0u}; std::index_sequence<I ...> = std::integer_sequence<unsigned int, 0u>]’
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/precise/core.hpp:140:52:   required from ‘void boost::pfr::for_each_field(T&&, F&&) [with T = Message&; F = main()::<lambda(const auto:7&)>]’
/tmp/untitled/main.cpp:13:60:   required from here
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/offset_based_getter.hpp:63:3: error: static assertion failed: ====================> Boost.PFR: Member sequence does not indicate correct size for struct type!
   static_assert(sizeof(U) == sizeof(S), "====================> Boost.PFR: Member sequence does not indicate correct size for struct type!");
   ^~~~~~~~~~~~~
In file included from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14_loophole.hpp:29:0,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14.hpp:13,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/precise/core.hpp:24,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/precise.hpp:12,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr.hpp:12,
                 from /tmp/untitled/main.cpp:2:
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/offset_based_getter.hpp:64:3: error: static assertion failed: ====================> Boost.PFR: Member sequence does not indicate correct alignment for struct type!
   static_assert(alignof(U) == alignof(S), "====================> Boost.PFR: Member sequence does not indicate correct alignment for struct type!");
   ^~~~~~~~~~~~~
In file included from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14.hpp:13:0,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/precise/core.hpp:24,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/precise.hpp:12,
                 from /opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr.hpp:12,
                 from /tmp/untitled/main.cpp:2:
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14_loophole.hpp: In instantiation of ‘void boost::pfr::detail::for_each_field_dispatcher(T&, F&&, std::index_sequence<I ...>) [with T = Message; F = boost::pfr::for_each_field(T&&, F&&) [with T = Message&; F = main()::<lambda(const auto:7&)>]::<lambda(auto:1&&)>; unsigned int ...I = {0u}; std::index_sequence<I ...> = std::integer_sequence<unsigned int, 0u>]’:
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/precise/core.hpp:140:52:   required from ‘void boost::pfr::for_each_field(T&&, F&&) [with T = Message&; F = main()::<lambda(const auto:7&)>]’
/tmp/untitled/main.cpp:13:60:   required from here
/opt/vrag/releases/private/cucchetf-vimar-agx-dbg-latest/sdk/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/boost/pfr/detail/core14_loophole.hpp:254:23: error: use of ‘boost::pfr::for_each_field(T&&, F&&)::<lambda(auto:1&&)> mutable [with auto:1 = boost::pfr::detail::sequence_tuple::tuple<std::allocator<char>&>; T = Message&; F = main()::<lambda(const auto:7&)>]’ before deduction of ‘auto’
     std::forward<F>(f)(
     ~~~~~~~~~~~~~~~~~~^
         boost::pfr::detail::tie_as_tuple_loophole_impl(t)
         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     );
     ~                  
distcc[16882] ERROR: compile /tmp/untitled/main.cpp on localhost failed
ninja: build stopped: subcommand failed.
18:02:49: The process "/home/cucchetf/tools/cmake/bin/cmake" exited with code 1.
Error while building/deploying project untitled (kit: Private SDK)
The kit Private SDK has configuration issues which might be the root cause for this problem.
When executing step "CMake Build"
18:02:49: Elapsed time: 00:02.

getting the name of the fields

Hey,

I just found this, and was taking a look at this:
http://apolukhin.github.io/magic_get/boost_precise_and_flat_reflectio/short_examples_for_the_impatient.html

// incrementing each field on 1:
boost::pfr::flat_for_each_field(var, [](auto& field) {
    field += 1;
});

Is there a quick function for getting the names of the fields as well so that reflection can be built more easily? e.g. in this case

struct bar {
    char character;
    foo f;
};

getting character and f as well.

tuple_size<>::value and 'private' keyword

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

class Test { // no ostream operator defined!
private:
    std::string s;
    int i;
    char c;
public:
    double d;
    float f;
};

int main() {
    std::cout << "Test has " << boost::pfr::tuple_size<Test>::value
        << " fields" << "\n";
}

This prints "Test has 1 fields". gcc 7.1.0, std=c++17. Is this intended behaviour? If I change private: to public:, I get "Test has 5 fields"

std::unique_ptr and MSVC build failed

Build failed on MSVC with the following code (but it does not on GCC or clang)

struct UniquePtr {
    std::unique_ptr<int> a;
};
static_assert (boost::pfr::tuple_size_v<UniquePtr> == 1);

To be more precise the following static_asserts trigger:

  1. Boost.PFR: Types with user specified constructors (non-aggregate initializable types) are not supported.
  2. Boost.PFR: If there's no other failed static asserts then something went wrong. Please report this issue to the github along with the structure you're reflecting.
    See more CI output on https://github.com/Malibushko/magic_get_test

Should it work like that or is this a bug?

Is it possible to get the member name

example

struct my_struct{
  std::string name;
  unsigned boost;
  int pfr;
};

my_struct val;
cout << get_name<0>(val) << " " << get_name<1>(val) <<   " " << get_name<2>(val)  << endl;
// print "name boost pfr"

This is very useful for json serialization

error: no type named 'basic_string_view' in namespace 'std'

Perhaps, it's just my system, but i got this error when compiling an example:

xx $ c++ -std=c++14 -I include example/quick_examples.cpp
In file included from example/quick_examples.cpp:13:
In file included from include/boost/pfr.hpp:12:
In file included from include/boost/pfr/precise.hpp:14:
In file included from include/boost/pfr/precise/ops.hpp:15:
In file included from include/boost/pfr/precise/io.hpp:17:
include/boost/pfr/detail/io.hpp:32:16: error: no type named 'basic_string_view' in namespace 'std'
    const std::basic_string_view<CharT, Traits>& s) noexcept {
          ~~~~~^
include/boost/pfr/detail/io.hpp:32:33: error: expected ')'
    const std::basic_string_view<CharT, Traits>& s) noexcept {
                                ^
include/boost/pfr/detail/io.hpp:31:26: note: to match this '('
inline auto quoted_helper(
                         ^
include/boost/pfr/detail/io.hpp:33:22: error: use of undeclared identifier 's'
  return std::quoted(s);
                     ^
3 errors generated.
xx $

So, i edited include/boost/pfr/detail/io.hpp to remove the basic_string_view declaration and just included the string_view header:

// Copyright (c) 2016-2017 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_PFR_DETAIL_IO_HPP
#define BOOST_PFR_DETAIL_IO_HPP
#pragma once

#include <boost/pfr/detail/config.hpp>

#include <boost/pfr/detail/sequence_tuple.hpp>
#include <iomanip>
#include <iosfwd>  // stream operators

// Forward declaration
// namespace std {
//   template <class CharT, class Traits> class basic_string_view;
// }
#include <string_view> // addded
...

The the example compiled and worked. thanks.

macOS 10.13.4 Beta (17E150g)
Apple LLVM version 9.0.0 (clang-900.0.39.2)
Target: x86_64-apple-darwin17.5.0

compile error on ms visual studio 2017(15.4.5) with /std:c++latest

I have latest compiler(at this moment ) and defined BOOST_PFR_USE_CPP17, but i got error around 'size_v' in 'tuple_size.hpp' header.

here:
template <class T> using flat_tuple_size = boost::pfr::detail::size_t_<decltype(boost::pfr::detail::tie_as_flat_tuple(std::declval<T&>()))::size_v>;

1>d:\consoleapplication1\3rdparty\pfr\include\boost\pfr\flat\tuple_size.hpp(26): error C2039: 'size_v': is not a member of '`global namespace''
1>d:\consoleapplication1\3rdparty\pfr\include\boost\pfr\flat\tuple_size.hpp(26): error C2146: syntax error: missing '>' before identifier 'size_v'
1>d:\consoleapplication1\3rdparty\pfr\include\boost\pfr\flat\tuple_size.hpp(26): error C2993: 'unknown-type': illegal type for non-type template parameter 'Index'

Nested arrays with C++ 17.

The following snippet compiles fine in C++14 mode but fails in C++17:

#include <boost/pfr/precise/core.hpp>

int main()
{
  struct foo
  {
    int things[3];
  };
  
  boost::pfr::for_each_field(foo{{1, 2, 3}}, [&](auto& field) {});
}

Tested on GCC 7.2.0 and CLANG 5.0.0.

Errors from CLANG:

In file included from main.cpp:5:
In file included from include/boost/pfr/precise/core.hpp:21:
In file included from include/boost/pfr/detail/core17.hpp:10:
include/boost/pfr/detail/core17_generated.hpp:57:9: error: type 'foo' decomposes into 1 elements, but 3 names were provided
auto& [a,b,c] = val;
^
include/boost/pfr/detail/core17_generated.hpp:1032:30: note: in instantiation of function template specialization 'boost::pfr::detail::tie_as_tuple'
requested here
return boost::pfr::detail::tie_as_tuple(val, fields_count_tag{});
^
include/boost/pfr/detail/core17.hpp:52:17: note: in instantiation of function template specialization 'boost::pfr::detail::tie_as_tuple' requested here
detail::tie_as_tuple(t)
^
include/boost/pfr/precise/core.hpp:145:27: note: in instantiation of function template specialization 'boost::pfr::detail::for_each_field_dispatcher<foo,
(lambda at include/boost/pfr/precise/core.hpp:147:9), 0, 1, 2>' requested here
::boost::pfr::detail::for_each_field_dispatcher(
^
main.cpp:102:15: note: in instantiation of function template specialization 'boost::pfr::for_each_field<foo, (lambda at main.cpp:102:46)>' requested here
boost::pfr::for_each_field(foo{{1, 2, 3}}, [&](auto& field) {});
^
1 error generated.

Errors from GCC:

In file included from include/boost/pfr/detail/core17.hpp:10:0,
from include/boost/pfr/precise/core.hpp:21,
from main.cpp:5:
include/boost/pfr/detail/core17_generated.hpp: In instantiation of ‘constexpr auto boost::pfr::detail::tie_as_tuple(T&, boost::pfr::detail::size_t_<3>) [with T = main()::foo; boost::pfr::detail::size_t_<3> = std::integral_constant<long unsigned int, 3>]’:
include/boost/pfr/detail/core17_generated.hpp:1032:42: required from ‘constexpr auto boost::pfr::detail::tie_as_tuple(T&) [with T = main()::foo]’
include/boost/pfr/detail/core17.hpp:52:29: required from ‘void boost::pfr::detail::for_each_field_dispatcher(T&, F&&, std::index_sequence<_Idx ...>) [with T = main()::foo; F = boost::pfr::for_each_field(T&&, F&&) [with T = main()::foo; F = main()::<lambda(auto:6&)>]::<lambda(auto:1&&)>; long unsigned int ...I = {0, 1, 2}; std::index_sequence<_Idx ...> = std::integer_sequence<long unsigned int, 0, 1, 2>]’
include/boost/pfr/precise/core.hpp:145:52: required from ‘void boost::pfr::for_each_field(T&&, F&&) [with T = main()::foo; F = main()::<lambda(auto:6&)>]’
main.cpp:102:65: required from here
include/boost/pfr/detail/core17_generated.hpp:57:9: error: 3 names provided while ‘main()::foo’ decomposes into 1 elements
auto& [a,b,c] = val;
^~~~~~~
In file included from include/boost/pfr/precise/core.hpp:21:0,
from main.cpp:5:
include/boost/pfr/detail/core17.hpp: In instantiation of ‘void boost::pfr::detail::for_each_field_dispatcher(T&, F&&, std::index_sequence<_Idx ...>) [with T = main()::foo; F = boost::pfr::for_each_field(T&&, F&&) [with T = main()::foo; F = main()::<lambda(auto:6&)>]::<lambda(auto:1&&)>; long unsigned int ...I = {0, 1, 2}; std::index_sequence<_Idx ...> = std::integer_sequence<long unsigned int, 0, 1, 2>]’:
include/boost/pfr/precise/core.hpp:145:52: required from ‘void boost::pfr::for_each_field(T&&, F&&) [with T = main()::foo; F = main()::<lambda(auto:6&)>]’
main.cpp:102:65: required from here
include/boost/pfr/detail/core17.hpp:51:23: error: invalid use of void expression
std::forward(f)(
~~~~~~~~~~~~~~~~~~^
detail::tie_as_tuple(t)
~~~~~~~~~~~~~~~~~~~~~~~
);
~

detail::fields_count<T>() returns different value for same type

Hello there, i ran into a problem where for the same type (typeid(T).hash_code is identical) the fields count is 0 when i call it from within another templated function. Its possible that this is a compiler (lastest msvc) problem and not directly related to your code as i have the same problem with a different approach. Maybe you have some insights regardless.

I filed a question at stackoverlfow: https://stackoverflow.com/questions/46675239/ describing my setup.

` template <class T, bool Assemble>
constexpr bool is_var_t(/const/ var_t<T, Assemble>& _Member) { return true; }

template <class T>
constexpr bool is_var_t(T& _Member) { return false; }

template <class T>
void InitVar(T& _Member) { std::cout << typeid(T).name() << std::endl; }

template <class T, bool Assemble>
void InitVar(var_t<T, Assemble>& _Member)	{std::cout << typeid(T).name() << std::endl;	}

template <size_t n, size_t N, class T>
void InitStruct(T& _Struct)
{
	std::cout << "n " << n << " N " << N << std::endl;
	if constexpr(n < N)
	{
		decltype(auto) member = hlx::get<n>(_Struct);
		using MemberType = std::remove_cv_t<decltype(member)>;
		std::cout << typeid(MemberType).hash_code() << std::endl;

		if (is_var_t(member))
		{
			InitVar(member);
			InitStruct<n + 1, N, T>(_Struct);
		}
		else
		{
			constexpr size_t M = boost::pfr::detail::fields_count<T>(); // asserts because result is always 0
			InitStruct<0, M, decltype(member)>(member);
		}
	}
}

template <class T, bool Assemble>
void InitializeStruct(T& _Struct)
{
	if constexpr(Assemble)
	{
		constexpr size_t N = boost::pfr::detail::fields_count<T>();
		InitStruct<0, N, T>(_Struct);
	}
}`

the same behaviour is visible here: http://coliru.stacked-crooked.com/a/b25a84454d53d8de

structs are:

`struct B
{
var_t<float4_t, true> f4;
};

struct A
{
B b;
};`

even if replace the var_t<> with a fundamental type like int, the problem persists.
Would you guess this is a compiler problem or is there a code solution?

A `uint8_t` value is printed as an ascii character (or nothing) for `std::ostream`

Because pfr uses the stream operator for native type printing, something like this:

struct A {
    uint8_t u8{49};
};

will print: {1} because the ascii value of decimal 49 happens to be "1". It would be blank if the uint8_t happened to be unprintable ascii - like 0.

And this is because std::ostream usually has a specialization for ostream& operator<<(ostream&, char), which will be found when the uint8_t gets implicitly converted to char (if it isn't already just a typedef for to begin with), when it's invoked like this in io.hpp's print_impl():

        out << detail::quoted_helper(boost::pfr::detail::sequence_tuple::get<I>(value));

Usually what people do is promote the uint8_t to an int by doing +value or casting; but in pfr's case it might be better to do it some other way.

Also, technically this issue applies to simple char, unsigned char and signed char members of classes/struct too. It's just not safe to output them directly using <<, unfortunately. (well... it's not unsafe - but it won't print what one would expect)

Detecting number and types of parameters in a function.

Not really an issue :-)
I was watching your talk about this fantastic library, and someone asked you "how to find the number and types of arguments of a function".

I'm using the following approach in my library. And it only works with lambda and functors. @apolukhin Sorry for throwing it here, but i will be really glad to know if this triggers any idea for you on how to support plain functions as well.

        template<typename> struct function_traits;

        template <typename Function>
        struct function_traits : public function_traits<
            decltype(&Function::operator())
        > { };

        template <
            typename    ClassType,
            typename    ReturnType,
            typename... Arguments
        >
        struct function_traits<
            ReturnType(ClassType::*)(Arguments...) const
        > {
            typedef ReturnType result_type;

            template <std::size_t Index>
            using argument = typename std::tuple_element<
                Index,
                std::tuple<Arguments...>
            >::type;

            static const std::size_t arity = sizeof...(Arguments);
        };

    /* support the non-const operator ()
     * this will work with user defined functors */
        template <
            typename    ClassType,
            typename    ReturnType,
            typename... Arguments
        >
        struct function_traits<
            ReturnType(ClassType::*)(Arguments...)
        > {
            typedef ReturnType result_type;

            template <std::size_t Index>
            using argument = typename std::tuple_element<
                Index,
                std::tuple<Arguments...>
            >::type;

            static const std::size_t arity = sizeof...(Arguments);
};

Is reinterpret_cast to layout compatible necessary?

Hi, I'm the same person as render787, I posted in the "great type loophole" thread on reddit. I was recently thinking about magic_get again :)

I'm not totally sure if my information about magic_get is up to date, I guess there has been a fair amount of development since the cppcon talk.

Anyways, from inspection of code for instance here https://github.com/apolukhin/magic_get/blob/master/include/boost/pfr/detail/cast_to_layout_compatible.hpp#L34

it appears to me that the classic, c++14 version works basically this way:

  1. Given user-defined struct T, we find the list of members, using trick with ubiq. We determine a typelist containing the struct members in sequence. (In C++14 this means the "flattened" members.)
  2. Given the typelist of members, we have a custom tuple type, which is supposed have the same layout as a struct with those members, on all compilers. (Assuming it is standard layout.) We can't use std::tuple for this because on some compilers std::tuple has members in the reverse order, the standard doesn't require that.
  3. Then we reintepret_cast the user-defined struct T to the tuple type, so that we can provide all the goodies for it. This is technically undefined behavior, but in practice it works, and magic_get tries to mark the pointers as potentially aliasing in order to prevent strict aliasing optimizations from breaking the code.

It occurred to me recently that potentially, the reinterpret cast to unrelated types could be avoided.

What I propose instead is:

2.5. Given the std::tuple which is layout compatible, compute a list of "offset" numbers. These numbers should be exactly the same as what would be computed by offsetof macro on the user-defined type.

  1. Given a user-defined structure instance, the typelist corresponding to it, and the offset list also, we can implement std::get, by taking pointer to structure, casting to char *, adding the offset, and reinterpet_cast to T * where T is the type. Then we make magic_get work through that impl of get instead of by the tuple get against the casted structure.

The advantage of this is that, this method of reinterpret_cast conforms to the C++ standard completely and the optimizer isn't allowed to break it. It doesn't involve reinterpret_cast of unrelated types -- char * is always allowed to alias, and the pointer that we cast to T* is indeed a legitimate pointer to T. It's discussed also on stack overflow: https://stackoverflow.com/questions/46123867/struct-offsets-and-pointer-safety-in-c

I think this method can also work even if the struct type T contains types that are not literal. Because, using the ubiq method, you can find the size and align of every member type. So imagine it would look like this:

Given

typelist <T1, T2, T3>

in a constexpr function, you can create

using matching_tuple_t = magic_get::tuple< std::aligned_storage<sizeof(T1), alignof(T1)>, std::aligned_storage<sizeof(T2), alignof(T2)>, std::aligned_storage<sizeof(T3), alignof(T3)> >

and matching_tuple_t can be constructed in a constexpr function even if T1, T2, T3 cannot be. You can construct it on the stack, then take differences of pointer to the tuple vs. pointer to the members in order to compute the correct list of offsets.

If you also use the loophole method for ubiq detection then I think this means that magic_get can work with any aggregate initializable, standard layout structure, without need for preregistering types or need for constexpr initializability of types. (I'm not sure though, does the ubiq part also need the type to be constexpr initializable? It would be cool if that restriction can be removed.)

I'm not sure if this post is clear,or if there are problems with my idea, but would you ptentially be interested in a pull request that tries this approach? From my point of view it would be really nice if that reinterpret cast can be removed, because I don't think anything else in magic_get is not kosher with the standard AFAIK.

Feature Request: allow specializing printing of native types

Hi,
First: nice library!

Second: is there a way we can overload or specialize printing of native types? For example the bool type - because I want it to print "true"/"false" not "1" or "0".

For example, would it be ok to specialize or overload boost::pfr::detail::quoted_helper()? It's in the detail namespace, so I assume we shouldn't; and besides I haven't gotten it to actually work because of the signature of quoted_helper()... but this is more about the general idea of doing so rather than the details.

I realize we can give our streamable a std::boolalpha, but doing that at every call site is annoying. And I'm not suggesting pfr's default behavior change either - I'd just like to customize it, if it's possible.(?)

Functions in core17_generated.hpp

How are the functions generated in core17_generated.hpp?

Are they generated by hand or by some tools?

https://github.com/apolukhin/magic_get/blob/develop/include/boost/pfr/detail/core17_generated.hpp

Error on gcc 10 with -std=c++20

/usr/local/ssd/projects/Labor/cpp20/magic/include/boost/pfr/detail/fields_count.hpp:233:53: error: static assertion failed: ====================>
Boost.PFR: Types with user specified constructors (non-aggregate initializable types) are not supported.
/usr/usr/local/ssd/projects/Labor/cpp20/magic/include/boost/pfr/detail/fields_count.hpp:233:53: error: static assertion failed: ====================>
Hello,

Just tried to compile the examples.cpp with gcc 10 with -std=c++20 flag enabled and got an static_assert error (see below). Removing the static_assert the samples is compiling.

Best regards,
Daniel

Boost.PFR: Types with user specified constructors (non-aggregate initializable types) are not supported.
/usr/local/ssd/projects/Labor/cpp20/magic/include/boost/pfr/detail/fields_count.hpp: In instantiation of ‘constexpr std::size_t boost::pfr::detail
::fields_count() [with T = my_struct_nested; std::size_t = long unsigned int]’:
/usr/local/ssd/projects/Labor/cpp20/magic/include/boost/pfr/detail/core14_loophole.hpp:158:67: required from ‘auto boost::pfr::detail::tie_as_tu
/local/ssd/projects/Labor/cpp20/magic/include/boost/pfr/detail/fields_count.hpp: In instantiation of ‘constexpr std::size_t boost::pfr::detail
::fields_count() [with T = my_struct_nested; std::size_t = long unsigned int]’:
/usr/local/ssd/projects/Labor/cpp20/magic/include/boost/pfr/detail/core14_loophole.hpp:158:67: required from ‘auto boost::pfr::detail::tie_as_tu

Underspecified semantics of functions and io

  • what are the requirements on fields
  • Common io questions: What format of the serialized output does the library guarantee? Does it guarantee any format at all? Do you leave yourself a freedom to change it in the future without notice? Can users customize it? If so, where is it specified?
  • refer to std:: alternatives (like std::tie in structure_tie)
  • "provides other std::tuple like methods for user defined types without any macro or boilerplate code." and BOOST_PFR_FUNCTIONS_FOR contradictions

A couple of comments

Hey Anton,
I just looked through the source code and was impressed by the number of smartest metaprogramming tricks. It literally made my brain exploded.
I have only a couple of comments to discuss:

  1. First, the requirement of using pod type seems to be too restrictive. IIUC what we need from a type is to be aggregate initializable and be able to convert via reinterpret_cast to an arbitrary structure. For this, standard_layout requirement seems to be good enough and would allow flat_type to be _somewhat_trivial*. Consider the following case:
struct A { // not trivial, yet aggregate_initializable class (in C++14)
    int a = 8;
    double b = im_not_trivial_but_long_running_function();
};
boost::pfr::flat_get<1>(A{});

On top of that, as flat types are ubiquitously used in constexpr context, it would be nice to static_assert on is_literal_type in the first place.
2. has_reference_members seems to just check whether members can be constructed from temporary objects. it doesn't cover cases when a reference is const or rvalue reference. I'm not sure, maybe it is not intented. Anyways, this requrement is already checked by is_pod, as is_pod implies is_standard_layout, which explicitly prohibits reference members.

Documentation of "precise" and "flat"

I think you should document what you mean by "precise" and "flat" in your library as part of an Overview section and before the Tutorial. It is very important for people to understand this as early as possible in the doc.

Quite easy to fail build due to compile recursion issues

#include "boost\pfr\precise.hpp"

struct test
{
    char data[256];
};

int main()
{
    test* val = new test;
    return boost::pfr::get<0>(*val);
}

...\boost\pfr\detail\fields_count.hpp(96): fatal error C1202: recursive type or function dependency context too complex

It also depends on the length of nested types names:

#include "boost\pfr\precise.hpp"

struct test
{
    unsigned data[65];
};

int main()
{
    test* val = new test;
    return (int)boost::pfr::get<0>(*val);
}
#include "boost\pfr\precise.hpp"
#include <array>

namespace geom
{
    template<typename T, size_t Rows, size_t Columns>
    struct matrix
    {
        std::array<std::array<T, Rows>, Columns> Data;
    };
}


struct test
{
    geom::matrix<float, 4, 4> data[4];
};

int main()
{
    test* val = new test;
    return (int)boost::pfr::get<0>(*val);
}

I understand that this example is synthetic but it is easy to achieve when you have big enough nested struct hierarchy (static array of matrices, etc). But it seems that this may be fixed (at least improved) by using fold expressions instead of recursion in implementation.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.