glaze icon indicating copy to clipboard operation
glaze copied to clipboard

C++ module interface

Open msqr1 opened this issue 11 months ago • 54 comments

I see your project using C++23, it doesn't have a C++ module support yet, and I could provide one using https://github.com/msqr1/importizer ? I would be happy to do this if you want!

msqr1 avatar Feb 01 '25 05:02 msqr1

I'd love to get a branch working with module support. Would it work across GCC, MSVC, and Clang? If you want to try and submit a pull request I'd love to see how much progress can be made. I do expect we might need to submit some bug reports because this is a large and complex project.

FYI, right now some of the Glaze tests do not build with the latest MSVC due to a recent compiler bug they introduced in 17.2. You can see #1448. We're pending the release of a fix.

stephenberry avatar Feb 01 '25 14:02 stephenberry

It can easy be done with better quality by hand than any auto converter to work with clang and gcc with CMake. C++ part is easy to do so. msvc AFIK does not have fully working modules at this time. CMake 3.31 works ok with modules. Worst is there is no support for code completion in various ide for imported modules so I am sceptic for using modules at production in large project and lose all ide code completion support. I makes sense to use modules for ex release build but this is not a case I would optimise for myself, rather I would expect optimising development for which it will not yet work in IDE.

such case works ok on clang

shared lib my_library.cxx

module ;
#include <string>

export module my_library;

export void do_something();

export template<typename T>
struct MyTemplate
  {
  T value;
  };

export struct MyStruct
  {
  int data;
  std::string str;  
  };

my_library.cpp

module;

#include <print>

module my_library;

void do_something() { std::print("Doing something!\n"); }
add_library(my_library SHARED)


target_sources(
  my_library
  PRIVATE src/my_library.cpp
  PUBLIC FILE_SET my_module_interface TYPE CXX_MODULES FILES
         "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/my_library.cxx>"
)

set_target_properties(
  my_library
  PROPERTIES CXX_STANDARD 23
             CXX_STANDARD_REQUIRED YES
             CXX_EXTENSIONS OFF
             CXX_SCAN_FOR_MODULES YES)

and using of module

import my_library;

int main()
  {
  do_something();

  MyTemplate<int> temp{42};

  MyStruct struct_ex{123, ""};

  return 0;
  }
cmake_minimum_required(VERSION 3.31)
project(my_project CXX)

set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_SCAN_FOR_MODULES ON)


add_subdirectory(my_library)

add_executable(my_executable src/main.cpp)
target_link_libraries(my_executable PRIVATE my_library)

install(TARGETS my_executable RUNTIME DESTINATION bin)
install(TARGETS my_library LIBRARY DESTINATION lib)

arturbac avatar Feb 02 '25 18:02 arturbac

More complicated it becomes in cmake configuration to maintain backward compatibility and option either to declare interface header only library or module library example, I am experimenting with simple_enum

option(SIMPLE_ENUM_ENABLE_MODULE "Export c++ module" ON)
if( SIMPLE_ENUM_ENABLE_MODULE)
  add_library(simple_enum)
  target_sources(
      simple_enum
      PRIVATE FILE_SET HEADERS BASE_DIRS
              $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
      PUBLIC FILE_SET CXX_MODULES FILES
             "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/module/simple_enum.cxx>"
    )
  set_target_properties(
    simple_enum
    PROPERTIES CXX_STANDARD 23
               CXX_STANDARD_REQUIRED YES
               CXX_EXTENSIONS OFF
               CXX_SCAN_FOR_MODULES YES)
else()
  add_library(simple_enum INTERFACE)
  target_sources(
    simple_enum
    INTERFACE FILE_SET
              HEADERS
              BASE_DIRS
              $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
              $<INSTALL_INTERFACE:include>)

  target_compile_features(simple_enum INTERFACE cxx_std_23)
endif()
if(SIMPLE_ENUM_OPT_IN_STATIC_ASSERTS)
  target_compile_definitions(simple_enum INTERFACE SIMPLE_ENUM_OPT_IN_STATIC_ASSERTS=1)
endif()

arturbac avatar Feb 02 '25 20:02 arturbac

BTW It is not about 'converting' into modules but to add optional module support , so additional c++ files declaring exports that can be ignored with normal pure include interface EDIT: And it is not about adding export at the top of includes and export everything including detail namespace, when someone does that it misses the point of using modules to export only public interface. For example I add file exporting selected elements of simple_enum only, skipping all private type and data.

module;
#include <simple_enum/simple_enum.hpp>
#include <simple_enum/enum_index.hpp>
#include <simple_enum/enum_cast.hpp>
#include <simple_enum/generic_error_category.hpp>
#include <simple_enum/generic_error_category_impl.hpp>
#include <simple_enum/ranges_views.hpp>
#include <simple_enum/std_format.hpp>

export module simple_enum;

export namespace simple_enum
  {
using simple_enum::v0_8::enum_concept;
using simple_enum::v0_8::bounded_enum;

using simple_enum::v0_8::adl_info;
using simple_enum::v0_8::info;
using simple_enum::v0_8::enum_name;
using simple_enum::v0_8::enum_name_t;

using simple_enum::v0_8::enum_index_error;
using simple_enum::v0_8::enum_index_t;
using simple_enum::v0_8::enum_index;
using simple_enum::v0_8::consteval_enum_index;

using simple_enum::v0_8::enum_cast_error;
using simple_enum::v0_8::enum_cast_t;
using simple_enum::v0_8::enum_cast;
[..]
  }  // namespace simple_enum

arturbac avatar Feb 02 '25 20:02 arturbac

Don't worry, importizer aims to reduce much trivial work only, of course we still have to do some fixing and cleaning up ourselves, it's not as smart as a human :(. The selling point is that the tool can do this kind of modularization for backward compatibility, optionally switching to modules with a single macro definition: https://github.com/msqr1/importizer/blob/main/Example.md#transitional-compilation-example . So you can still keep literally everything as-is.

In addition, it is not wrapping the header interface to export things, it is literally going to modularize it into a hybrid interface, supporting the global module migration.

But yeah, I do agree that linting is a bit annoying right now.

msqr1 avatar Feb 02 '25 23:02 msqr1

IMHO mixing module and non module code with conditional macro definitions is low quality code hard to maintain and at the end difficult to read.

EDIT: From last talk about module support is to not create files with *m mdoule extensions, just pure normal cc, cpp, cxx because AFIR there are already some problems with support for that in compilers.

arturbac avatar Feb 02 '25 23:02 arturbac

Btw for modules support You need to have 3.28

cmake_minimum_required(VERSION 3.28..3.31)

arturbac avatar Feb 02 '25 23:02 arturbac

Or you can just modularize it completely and maintain both the header ones and the module one. That would be tiring and repeating lots of code, though IMHO. Or you can just wrap it, but that wouldn't help with the global module migration :(.

About maintainability, I find that aside from the section on top of the file, everything else is the same, isn't it? At the end of the day, let's try and see how Stephen feels about it.

Also, the tool provides many options, including toggling the output extension. See more in the setting section of the README.

msqr1 avatar Feb 02 '25 23:02 msqr1

I will give You and idea if You are a dev of this tool and maybe interested in that ..

With cmake You can get targets and its sources etc.. With libclang You can use AST to examine parsed code. IMHO valuable would be a tool generating module file exporting everything for specified namespace and including proper incldues for given target from ccmake and it sources as below

module;
// include deps required for exported type
export module my_name;
// scanned output of types, classes, functions, and variables.

That would be very valuable tool for ppl with large projects, because You would be able to understand the result and maintain it.

arturbac avatar Feb 03 '25 00:02 arturbac

In ideal world we would liek to just convert our projects into module versions , but we ca not and we will not be able to do so for a long time .. IMHO separate files with explicit content being exported is better to maintain that conditional macros everywhere in code ..

arturbac avatar Feb 03 '25 00:02 arturbac

Or you can just modularize it completely and maintain both the header ones and the module one.

This is not feasible to maintain and not rational double the possibility of introducing bugs.

arturbac avatar Feb 03 '25 00:02 arturbac

Btw the decision is in Stephan's hands, I have nothing to do with it except to advise.

arturbac avatar Feb 03 '25 00:02 arturbac

Yeah, I am also planning for that, not only modularizing, but also wrapping the header intetface into a module. Right now I have only modularization (because I want to help with the migration), so I didn't implement wrapping yet, but it is also a good option to have.

Although I feel like this is done by hand really easily, just do some #include, and a big export block, right? Actual modularizing is way harder, that's why I made the tool.

IMHO separate files with explicit content being exported is better to maintain that conditional macros everywhere in code

This is right, but the hybrid form doesn't have conditional macros everywhere. It's only in the top section, there is no more conditional macros down below.

Also, we shouldn't be discussing extension to importizer here, can you make an issue there and we'll continue?

msqr1 avatar Feb 03 '25 00:02 msqr1

This is right, but the hybrid form doesn't have conditional macros everywhere. It's only in the top section, there is no more conditional macros down below.

What about 90% of most incldues content in detail namespaces ? export everything ?

arturbac avatar Feb 03 '25 00:02 arturbac

There is an EXPORT macro (like assert) that is defined to be export when modules are on, and nothing when it's off. This is done in a separate file (no pollution) that is included automatically, so you can just place the EXPORT before whatever you want and be done! It's just a minimal replacement for the export keyword. Don't worry, it will get just a bit dirty at the top and no more.

A lot of people are probably confused like you, so maybe I should add an FAQ section 😆.

msqr1 avatar Feb 03 '25 00:02 msqr1

@stephenberry I finished module support in simple_enum except glaze dedicated header .. So I wonder how to introduce module support for glaze in simple_enum with this glaze dedicated header in simple enum. I would export it as separate module ie simple_enum.glaze but ..

That requires some version of glaze to be used for exporting empty/hidden content module, and then this restricts users to use that version of glaze .. So making module for this make an dependency injection early I am not 100% sure but it will look like in the future but maybe something like that ..

module;
import glaze;
#define SIMPLE_ENUM_SKIP_INCLUDING_GLAZE // for below header skipping inclusion of glaze headers
#include <simple_enum/glaze_json_enum_name.hpp> // for declaring from/to specializations

export simple_enum.glaze;
// everything hidden

arturbac avatar Feb 03 '25 00:02 arturbac

There is an EXPORT macro (like assert)

A lot of people are probably confused like you, so maybe I should add an FAQ section 😆.

I am sorry but I didn't pay much attention to Your project because I don't use macros 99% of the time. When there is some solution offered to me with macros I usually just ignore it ... Only in rare cases when there is no other option to use pure language i use macros but not in such case as whole project with conditionals and macro expansion.

arturbac avatar Feb 03 '25 00:02 arturbac

From my module simple enum experiment with modules

  • clang-20 libc++, libstdc++14 - everything is perfectly OK
  • clang-19 libc++ - OK
  • clang-19 libstdc++14 - FAILS in stdc++ ranges g++-v14/ranges:9468:11: error: type alias template redefinition with different types
  • gcc-14 - FAILS with some nonsense error: failed to read compiled module: Bad file data
  • msvc - even does not support c++23 static operator()

IMHO it is a long road to stable modules and it is not yet worth work except for clang witch is in good shape so far.

arturbac avatar Feb 03 '25 12:02 arturbac

Thanks for all the helpful thoughts and notes here. I've done some module experimentation and was waiting for better GCC support before continuing, but I am eager to see what others are able to acheive.

Some thoughts:

  • When moving Glaze to C++20 modules I want to move to pure modules. Glaze only depends on the standard library, so there is no need for an intermediate approach that mixes headers and modules. Glaze will still need to be used with a header include approach, but if the user wants Glaze as a module, #include should not exist within the Glaze module. This means that import std must be supported for any compiler that we want to use for modular Glaze. We are waiting on GCC 15 for import std. But, I would be happy getting modules with Glaze just working on Clang for now.
  • Using macros to conditionally create a module in C++ is not valid and MSVC will issue warnings. So, I think the current approach of importizer is incorrect (@msqr1 do you not see these warnings with MSVC?).

stephenberry avatar Feb 03 '25 16:02 stephenberry

When moving Glaze to C++20 modules I want to move to pure modules. Glaze only depends on the standard library, so there is no need for an intermediate approach that mixes headers and modules.

I have a configuration for that in importizer

Glaze will still need to be used with a header include approach, but if the user wants Glaze as a module, #include should not exist within the Glaze module. This means that import std must be supported for any compiler that we want to use for modular Glaze.

Compiler support for import std is not very good right now TBH. Importizer does have settings to turn STL includes into import std/std.compat

Using macros to conditionally create a module in C++ is not valid and MSVC will issue warnings. So, I think the current approach of importizer is incorrect (@msqr1 do you not see these warnings with MSVC?).

I am only working on clang right now, importizer is really new. Btw, could you show me the warnings? I don't have MSVC on me :(. I checked the C++ standard, doing so is fine, it's just weird MSVC. On my machine, clang is fine, no warning, you can even keep the same CMakeLists.txt to compile in header mode.

If you still want a header and the module, you can still wrap it in a big module interface

msqr1 avatar Feb 03 '25 18:02 msqr1

Thanks for your response! Your project seems really neat. I to dig up my module testing work. For now I'll trust your expertise because you have a lot more experience with this than me.

stephenberry avatar Feb 03 '25 19:02 stephenberry

I have a problem. When modularizing the include directory, some of the files use pragma once, and some of them uses include guard (include/glaze/dragonbox). And that is confusing the tool. Do you know why this is the case, and can I normalize it to just pragma once or just include guard? @stephenberry

msqr1 avatar Feb 03 '25 20:02 msqr1

You can change it to just use pragma once.

stephenberry avatar Feb 03 '25 21:02 stephenberry

@stephenberry I was compiling the source code with clang(++) with -v output:

Debian clang version 19.1.7 (++20250114103228+cd708029e0b2-1~exp1~20250114103334.78)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/lib/llvm-19/bin

(I was trying to test with fuzzing because my gcc doesn't support libfuzzer) when I got a bunch of errors. There is no modification made to the source.

[0/2] Re-checking globbed directories...
[1/4] Building CXX object tests/json_test/CMakeFiles/json_test.dir/json_test.cpp.o
FAILED: tests/json_test/CMakeFiles/json_test.dir/json_test.cpp.o 
/usr/bin/clang++-19 -DGLZ_USE_AVX2 -Iglaze-modularized/include -isystem glaze-modularized/build/_deps/ut-src/include -fno-exceptions -fno-rtti -Wall -Wextra -pedantic -ftime-trace -fsanitize=address -fsanitize-address-use-after-scope -fsanitize=undefined -Wno-missing-braces -mavx2 -std=gnu++2b -MD -MT tests/json_test/CMakeFiles/json_test.dir/json_test.cpp.o -MF tests/json_test/CMakeFiles/json_test.dir/json_test.cpp.o.d -o tests/json_test/CMakeFiles/json_test.dir/json_test.cpp.o -c glaze-modularized/tests/json_test/json_test.cpp
In file included from glaze-modularized/tests/json_test/json_test.cpp:26:
In file included from glaze-modularized/include/glaze/api/impl.hpp:24:
In file included from glaze-modularized/include/glaze/glaze.hpp:41:
In file included from glaze-modularized/include/glaze/json.hpp:6:
glaze-modularized/include/glaze/json/escape_unicode.hpp:242:22: error: constexpr variable 'escaped' must be initialized by a constant expression
  242 |       constexpr auto escaped = []() constexpr {
      |                      ^         ~~~~~~~~~~~~~~~~
  243 |          constexpr auto len = detail::escaped_length(Str.sv());
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  244 |          std::array<char, len + 1> result; // + 1 for null character
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  245 |          const auto escaped = detail::escape_json_string(Str.sv(), len);
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  246 |          for (size_t i = 0; i < len; ++i) {
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  247 |             result[i] = escaped[i];
      |             ~~~~~~~~~~~~~~~~~~~~~~~
  248 |          }
      |          ~
  249 |          result[len] = '\0';
      |          ~~~~~~~~~~~~~~~~~~~
  250 |          return result;
      |          ~~~~~~~~~~~~~~
  251 |       }();
      |       ~~~
glaze-modularized/include/glaze/json/escape_unicode.hpp:241:78: note: while substituting into a lambda expression here
  241 |    inline constexpr auto escape_unicode = []() constexpr -> std::string_view {
      |                                                                              ^
glaze-modularized/tests/json_test/json_test.cpp:4490:58: note: in instantiation of variable template specialization 'glz::escape_unicode' requested here
 4490 |    static constexpr auto value = object("ᇿ", &T::text, escape_unicode<"ᇿ">, &T::text);
      |                                                        ^
/usr/lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/basic_string.h:356:10: note: assignment to member '_M_local_buf' of union with no active member is not allowed in a constant expression
  356 |             __c = _CharT();
      |                 ^
/usr/lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/basic_string.h:519:2: note: in call to 'this->_M_use_local_data()'
  519 |         _M_use_local_data();
      |         ^~~~~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/json/escape_unicode.hpp:124:19: note: in call to 'basic_string()'
  124 |       std::string output;
      |                   ^~~~~~
glaze-modularized/include/glaze/json/escape_unicode.hpp:245:31: note: in call to 'escape_json_string({3, &<template param string_literal<4>{{-31, -121, -65, 0}}>.value[0]}, 6)'
  245 |          const auto escaped = detail::escape_json_string(Str.sv(), len);
      |                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/json/escape_unicode.hpp:242:32: note: in call to '[]() {
    constexpr auto len = detail::escaped_length(string_literal<4>{{-31, -121, -65, 0}}.sv());
    std::array<char, len + 1> result;
    const auto escaped = detail::escape_json_string(string_literal<4>{{-31, -121, -65, 0}}.sv(), len);
    for (size_t i = 0; i < len; ++i) {
        result[i] = escaped[i];
    }
    result[len] = '\x00';
    return result;
}.operator()()'
  242 |       constexpr auto escaped = []() constexpr {
      |                                ^~~~~~~~~~~~~~~~
  243 |          constexpr auto len = detail::escaped_length(Str.sv());
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  244 |          std::array<char, len + 1> result; // + 1 for null character
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  245 |          const auto escaped = detail::escape_json_string(Str.sv(), len);
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  246 |          for (size_t i = 0; i < len; ++i) {
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  247 |             result[i] = escaped[i];
      |             ~~~~~~~~~~~~~~~~~~~~~~~
  248 |          }
      |          ~
  249 |          result[len] = '\0';
      |          ~~~~~~~~~~~~~~~~~~~
  250 |          return result;
      |          ~~~~~~~~~~~~~~
  251 |       }();
      |       ~~~
glaze-modularized/include/glaze/json/escape_unicode.hpp:254:39: error: non-type template argument is not a constant expression
  254 |       auto& arr = detail::make_static<escaped>::value;
      |                                       ^~~~~~~
glaze-modularized/include/glaze/json/escape_unicode.hpp:254:39: note: initializer of 'escaped' is not a constant expression
glaze-modularized/include/glaze/json/escape_unicode.hpp:254:39: note: in call to 'array(escaped)'
  254 |       auto& arr = detail::make_static<escaped>::value;
      |                                       ^~~~~~~
glaze-modularized/include/glaze/json/escape_unicode.hpp:242:22: note: declared here
  242 |       constexpr auto escaped = []() constexpr {
      |                      ^
glaze-modularized/include/glaze/json/escape_unicode.hpp:241:26: error: constexpr variable 'escape_unicode<string_literal<4>{{-31, -121, -65, 0}}>' must be initialized by a constant expression
  241 |    inline constexpr auto escape_unicode = []() constexpr -> std::string_view {
      |                          ^                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  242 |       constexpr auto escaped = []() constexpr {
      |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  243 |          constexpr auto len = detail::escaped_length(Str.sv());
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  244 |          std::array<char, len + 1> result; // + 1 for null character
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  245 |          const auto escaped = detail::escape_json_string(Str.sv(), len);
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  246 |          for (size_t i = 0; i < len; ++i) {
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  247 |             result[i] = escaped[i];
      |             ~~~~~~~~~~~~~~~~~~~~~~~
  248 |          }
      |          ~
  249 |          result[len] = '\0';
      |          ~~~~~~~~~~~~~~~~~~~
  250 |          return result;
      |          ~~~~~~~~~~~~~~
  251 |       }();
      |       ~~~~
  252 | 
  253 |       // make_static here required for GCC 12, in the future just make escaped static
      |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  254 |       auto& arr = detail::make_static<escaped>::value;
      |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  255 |       return {arr.data(), arr.size() - 1};
      |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  256 |    }();
      |    ~~~
glaze-modularized/tests/json_test/json_test.cpp:4490:58: note: in instantiation of variable template specialization 'glz::escape_unicode' requested here
 4490 |    static constexpr auto value = object("ᇿ", &T::text, escape_unicode<"ᇿ">, &T::text);
      |                                                        ^
/usr/lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/basic_string.h:356:10: note: assignment to member '_M_local_buf' of union with no active member is not allowed in a constant expression
  356 |             __c = _CharT();
      |                 ^
/usr/lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/basic_string.h:519:2: note: in call to 'this->_M_use_local_data()'
  519 |         _M_use_local_data();
      |         ^~~~~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/json/escape_unicode.hpp:124:19: note: in call to 'basic_string()'
  124 |       std::string output;
      |                   ^~~~~~
glaze-modularized/include/glaze/json/escape_unicode.hpp:245:31: note: in call to 'escape_json_string({3, &<template param string_literal<4>{{-31, -121, -65, 0}}>.value[0]}, 6)'
  245 |          const auto escaped = detail::escape_json_string(Str.sv(), len);
      |                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/json/escape_unicode.hpp:242:32: note: in call to '[]() {
    constexpr auto len = detail::escaped_length(string_literal<4>{{-31, -121, -65, 0}}.sv());
    std::array<char, len + 1> result;
    const auto escaped = detail::escape_json_string(string_literal<4>{{-31, -121, -65, 0}}.sv(), len);
    for (size_t i = 0; i < len; ++i) {
        result[i] = escaped[i];
    }
    result[len] = '\x00';
    return result;
}.operator()()'
  242 |       constexpr auto escaped = []() constexpr {
      |                                ^~~~~~~~~~~~~~~~
  243 |          constexpr auto len = detail::escaped_length(Str.sv());
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  244 |          std::array<char, len + 1> result; // + 1 for null character
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  245 |          const auto escaped = detail::escape_json_string(Str.sv(), len);
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  246 |          for (size_t i = 0; i < len; ++i) {
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  247 |             result[i] = escaped[i];
      |             ~~~~~~~~~~~~~~~~~~~~~~~
  248 |          }
      |          ~
  249 |          result[len] = '\0';
      |          ~~~~~~~~~~~~~~~~~~~
  250 |          return result;
      |          ~~~~~~~~~~~~~~
  251 |       }();
      |       ~~~
glaze-modularized/include/glaze/json/escape_unicode.hpp:241:43: note: in call to '[]() -> std::string_view {
    constexpr auto escaped = []() {
        constexpr auto len = detail::escaped_length(string_literal<4>{{-31, -121, -65, 0}}.sv());
        std::array<char, len + 1> result;
        const auto escaped = detail::escape_json_string(string_literal<4>{{-31, -121, -65, 0}}.sv(), len);
        for (size_t i = 0; i < len; ++i) {
            result[i] = escaped[i];
        }
        result[len] = '\x00';
        return result;
    }();
    auto &arr;
    return {<recovery-expr>().data(), <recovery-expr>().size() - 1};
}.operator()()'
  241 |    inline constexpr auto escape_unicode = []() constexpr -> std::string_view {
      |                                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  242 |       constexpr auto escaped = []() constexpr {
      |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  243 |          constexpr auto len = detail::escaped_length(Str.sv());
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  244 |          std::array<char, len + 1> result; // + 1 for null character
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  245 |          const auto escaped = detail::escape_json_string(Str.sv(), len);
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  246 |          for (size_t i = 0; i < len; ++i) {
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  247 |             result[i] = escaped[i];
      |             ~~~~~~~~~~~~~~~~~~~~~~~
  248 |          }
      |          ~
  249 |          result[len] = '\0';
      |          ~~~~~~~~~~~~~~~~~~~
  250 |          return result;
      |          ~~~~~~~~~~~~~~
  251 |       }();
      |       ~~~~
  252 | 
  253 |       // make_static here required for GCC 12, in the future just make escaped static
      |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  254 |       auto& arr = detail::make_static<escaped>::value;
      |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  255 |       return {arr.data(), arr.size() - 1};
      |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  256 |    }();
      |    ~~~
glaze-modularized/tests/json_test/json_test.cpp:4490:26: error: constexpr variable 'value' must be initialized by a constant expression
 4490 |    static constexpr auto value = object("ᇿ", &T::text, escape_unicode<"ᇿ">, &T::text);
      |                          ^       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/core/common.hpp:538:35: note: initializer of 'escape_unicode<string_literal<4>{{-31, -121, -65, 0}}>' is not a constant expression
  538 |       return detail::Object{tuple{std::forward<Args>(args)...}};
      |                                   ^
glaze-modularized/include/glaze/core/common.hpp:538:35: note: in call to 'basic_string_view(escape_unicode)'
  538 |       return detail::Object{tuple{std::forward<Args>(args)...}};
      |                                   ^~~~~~~~~~~~~~~~~~~~~~~~
glaze-modularized/tests/json_test/json_test.cpp:4490:34: note: in call to 'object<const char (&)[4], std::basic_string<char> question_escaped_t::*, const std::basic_string_view<char> &, std::basic_string<char> question_escaped_t::*>("\341\207\277", &T::text, escape_unicode, &T::text)'
 4490 |    static constexpr auto value = object("ᇿ", &T::text, escape_unicode<"ᇿ">, &T::text);
      |                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/json/escape_unicode.hpp:241:26: note: declared here
  241 |    inline constexpr auto escape_unicode = []() constexpr -> std::string_view {
      |                          ^
glaze-modularized/tests/json_test/json_test.cpp:4493:15: error: static assertion expression is not an integral constant expression
 4493 | static_assert(glz::escape_unicode<"ᇿ"> == R"(\u11FF)");
      |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
glaze-modularized/tests/json_test/json_test.cpp:4493:15: note: initializer of 'escape_unicode<string_literal<4>{{-31, -121, -65, 0}}>' is not a constant expression
glaze-modularized/tests/json_test/json_test.cpp:4493:15: note: in call to 'basic_string_view(escape_unicode)'
 4493 | static_assert(glz::escape_unicode<"ᇿ"> == R"(\u11FF)");
      |               ^~~~~~~~~~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/json/escape_unicode.hpp:241:26: note: declared here
  241 |    inline constexpr auto escape_unicode = []() constexpr -> std::string_view {
      |                          ^
In file included from glaze-modularized/tests/json_test/json_test.cpp:26:
In file included from glaze-modularized/include/glaze/api/impl.hpp:6:
In file included from glaze-modularized/include/glaze/api/api.hpp:12:
In file included from glaze-modularized/include/glaze/api/std/string.hpp:9:
glaze-modularized/include/glaze/core/meta.hpp:117:36: error: constexpr variable 'meta_wrapper_v<question_escaped_t>' must be initialized by a constant expression
  117 |    inline constexpr decltype(auto) meta_wrapper_v = [] {
      |                                    ^                ~~~~
  118 |       if constexpr (detail::local_meta_t<T>) {
      |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  119 |          return T::glaze::value;
      |          ~~~~~~~~~~~~~~~~~~~~~~~
  120 |       }
      |       ~
  121 |       else if constexpr (detail::global_meta_t<T>) {
      |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  122 |          return meta<T>::value;
      |          ~~~~~~~~~~~~~~~~~~~~~~
  123 |       }
      |       ~
  124 |       else {
      |       ~~~~~~
  125 |          return empty{};
      |          ~~~~~~~~~~~~~~~
  126 |       }
      |       ~
  127 |    }();
      |    ~~~
glaze-modularized/include/glaze/core/meta.hpp:156:58: note: in instantiation of variable template specialization 'glz::meta_wrapper_v' requested here
  156 |    using meta_wrapper_t = decay_keep_volatile_t<decltype(meta_wrapper_v<std::decay_t<T>>)>;
      |                                                          ^
glaze-modularized/include/glaze/core/common.hpp:381:65: note: in instantiation of template type alias 'meta_wrapper_t' requested here
  381 |       concept glaze_array_t = glaze_t<T> && is_specialization_v<meta_wrapper_t<T>, Array>;
      |                                                                 ^
glaze-modularized/include/glaze/core/common.hpp:381:45: note: while substituting template arguments into constraint expression here
  381 |       concept glaze_array_t = glaze_t<T> && is_specialization_v<meta_wrapper_t<T>, Array>;
      |                                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/core/common.hpp:395:26: note: while checking the satisfaction of concept 'glaze_array_t<question_escaped_t>' requested here
  395 |          glaze_t<T> && !(glaze_array_t<T> || glaze_object_t<T> || glaze_enum_t<T> || meta_keys<T> || glaze_flags_t<T>);
      |                          ^~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/core/common.hpp:395:24: note: while substituting template arguments into constraint expression here
  395 |          glaze_t<T> && !(glaze_array_t<T> || glaze_object_t<T> || glaze_enum_t<T> || meta_keys<T> || glaze_flags_t<T>);
      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/json/read.hpp:126:19: note: (skipping 6 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
  126 |          requires(glaze_value_t<T> && !custom_read<T>)
      |                   ^
glaze-modularized/include/glaze/core/opts.hpp:345:34: note: while substituting template arguments into constraint expression here
  345 |    concept read_json_supported = requires { detail::from<JSON, std::remove_cvref_t<T>>{}; };
      |                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/json/read.hpp:2738:14: note: while checking the satisfaction of concept 'read_json_supported<question_escaped_t>' requested here
 2738 |    template <read_json_supported T, is_buffer Buffer>
      |              ^
glaze-modularized/include/glaze/json/read.hpp:2738:14: note: while substituting template arguments into constraint expression here
 2738 |    template <read_json_supported T, is_buffer Buffer>
      |              ^~~~~~~~~~~~~~~~~~~
glaze-modularized/tests/json_test/json_test.cpp:4534:18: note: while checking constraint satisfaction for template 'read_json<question_escaped_t, std::basic_string<char> &>' required here
 4534 |       expect(not glz::read_json(obj, str));
      |                  ^~~
glaze-modularized/tests/json_test/json_test.cpp:4534:18: note: in instantiation of function template specialization 'glz::read_json<question_escaped_t, std::basic_string<char> &>' requested here
glaze-modularized/include/glaze/core/meta.hpp:122:17: note: initializer of 'value' is not a constant expression
  122 |          return meta<T>::value;
      |                 ^
glaze-modularized/include/glaze/core/meta.hpp:122:17: note: in call to 'Object(value)'
  122 |          return meta<T>::value;
      |                 ^~~~~~~~~~~~~~
glaze-modularized/include/glaze/core/meta.hpp:117:53: note: in call to '[] {
    if (detail::local_meta_t<question_escaped_t>) {
    } else if (detail::global_meta_t<question_escaped_t>) {
        return meta<question_escaped_t>::value;
    } else {
    }
}.operator()()'
  117 |    inline constexpr decltype(auto) meta_wrapper_v = [] {
      |                                                     ^~~~
  118 |       if constexpr (detail::local_meta_t<T>) {
      |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  119 |          return T::glaze::value;
      |          ~~~~~~~~~~~~~~~~~~~~~~~
  120 |       }
      |       ~
  121 |       else if constexpr (detail::global_meta_t<T>) {
      |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  122 |          return meta<T>::value;
      |          ~~~~~~~~~~~~~~~~~~~~~~
  123 |       }
      |       ~
  124 |       else {
      |       ~~~~~~
  125 |          return empty{};
      |          ~~~~~~~~~~~~~~~
  126 |       }
      |       ~
  127 |    }();
      |    ~~~
glaze-modularized/tests/json_test/json_test.cpp:4490:26: note: declared here
 4490 |    static constexpr auto value = object("ᇿ", &T::text, escape_unicode<"ᇿ">, &T::text);
      |                          ^
In file included from glaze-modularized/tests/json_test/json_test.cpp:26:
In file included from glaze-modularized/include/glaze/api/impl.hpp:6:
In file included from glaze-modularized/include/glaze/api/api.hpp:12:
In file included from glaze-modularized/include/glaze/api/std/string.hpp:9:
glaze-modularized/include/glaze/core/meta.hpp:143:26: error: constexpr variable 'meta_v<question_escaped_t>' must be initialized by a constant expression
  143 |    inline constexpr auto meta_v = []() -> decltype(auto) {
      |                          ^        ~~~~~~~~~~~~~~~~~~~~~~~~
  144 |       if constexpr (detail::meta_keys<T>) {
      |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  145 |          return meta_wrapper_v<decay_keep_volatile_t<T>>;
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  146 |       }
      |       ~
  147 |       else {
      |       ~~~~~~
  148 |          return meta_wrapper_v<decay_keep_volatile_t<T>>.value;
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  149 |       }
      |       ~
  150 |    }();
      |    ~~~
glaze-modularized/include/glaze/core/meta.hpp:153:50: note: in instantiation of variable template specialization 'glz::meta_v' requested here
  153 |    using meta_t = decay_keep_volatile_t<decltype(meta_v<T>)>;
      |                                                  ^
glaze-modularized/include/glaze/core/reflect.hpp:90:30: note: in instantiation of template type alias 'meta_t' requested here
   90 |                (tuple_size_v<meta_t<T>> == 0))
      |                              ^
glaze-modularized/include/glaze/core/reflect.hpp:90:17: note: while substituting template arguments into constraint expression here
   90 |                (tuple_size_v<meta_t<T>> == 0))
      |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/json/read.hpp:1787:49: note: while checking constraint satisfaction for class template partial specialization 'reflect<question_escaped_t>' required here
 1787 |             static constexpr auto num_members = reflect<T>::size;
      |                                                 ^~~~~~~
glaze-modularized/include/glaze/json/read.hpp:1787:49: note: during template argument deduction for class template partial specialization 'reflect<T>' [with T = question_escaped_t]
glaze-modularized/include/glaze/json/read.hpp:1787:49: note: in instantiation of template class 'glz::reflect<question_escaped_t>' requested here
glaze-modularized/include/glaze/json/read.hpp:74:40: note: in instantiation of function template specialization 'glz::detail::from<10, question_escaped_t>::op<opts{10, 1, 0, 1, 1, 1, 0, 0, 32, 3, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 32}, string_literal<1>{""}, question_escaped_t &, glz::context &, const char *&, const char *&>' requested here
   74 |                from<JSON, V>::template op<Opts>(std::forward<T>(value), std::forward<Ctx>(ctx), std::forward<It0>(it),
      |                                        ^
glaze-modularized/include/glaze/core/read.hpp:60:46: note: in instantiation of function template specialization 'glz::detail::read<10>::op<opts{10, 1, 0, 1, 1, 1, 0, 0, 32, 3, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 32}, question_escaped_t &, glz::context &, const char *&, const char *&>' requested here
   60 |          detail::read<Opts.format>::template op<is_padded_on<Opts>()>(value, ctx, it, end);
      |                                              ^
glaze-modularized/include/glaze/json/read.hpp:2742:14: note: in instantiation of function template specialization 'glz::read<opts{10, 1, 0, 1, 1, 1, 0, 0, 32, 3, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0}, question_escaped_t, std::basic_string<char> &, glz::context &>' requested here
 2742 |       return read<opts{}>(value, std::forward<Buffer>(buffer), ctx);
      |              ^
glaze-modularized/tests/json_test/json_test.cpp:4534:23: note: in instantiation of function template specialization 'glz::read_json<question_escaped_t, std::basic_string<char> &>' requested here
 4534 |       expect(not glz::read_json(obj, str));
      |                       ^
glaze-modularized/include/glaze/core/meta.hpp:148:17: note: initializer of 'meta_wrapper_v<question_escaped_t>' is not a constant expression
  148 |          return meta_wrapper_v<decay_keep_volatile_t<T>>.value;
      |                 ^
glaze-modularized/include/glaze/core/meta.hpp:148:17: note: in call to 'tuple(meta_wrapper_v.value)'
  148 |          return meta_wrapper_v<decay_keep_volatile_t<T>>.value;
      |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/core/meta.hpp:143:35: note: in call to '[]() -> glz::tuple<const char *, std::basic_string<char> question_escaped_t::*, std::basic_string_view<char>, std::basic_string<char> question_escaped_t::*> {
    if (detail::meta_keys<question_escaped_t>) {
    } else {
        return meta_wrapper_v<decay_keep_volatile_t<question_escaped_t>>.value;
    }
}.operator()()'
  143 |    inline constexpr auto meta_v = []() -> decltype(auto) {
      |                                   ^~~~~~~~~~~~~~~~~~~~~~~~
  144 |       if constexpr (detail::meta_keys<T>) {
      |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  145 |          return meta_wrapper_v<decay_keep_volatile_t<T>>;
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  146 |       }
      |       ~
  147 |       else {
      |       ~~~~~~
  148 |          return meta_wrapper_v<decay_keep_volatile_t<T>>.value;
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  149 |       }
      |       ~
  150 |    }();
      |    ~~~
glaze-modularized/include/glaze/core/meta.hpp:117:36: note: declared here
  117 |    inline constexpr decltype(auto) meta_wrapper_v = [] {
      |                                    ^
In file included from glaze-modularized/tests/json_test/json_test.cpp:26:
In file included from glaze-modularized/include/glaze/api/impl.hpp:6:
In file included from glaze-modularized/include/glaze/api/api.hpp:13:
In file included from glaze-modularized/include/glaze/api/trait.hpp:11:
glaze-modularized/include/glaze/core/reflect.hpp:110:29: error: constexpr variable 'values' must be initialized by a constant expression
  110 |       static constexpr auto values = [] {
      |                             ^        ~~~~
  111 |          return [&]<size_t... I>(std::index_sequence<I...>) { //
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  112 |             return tuple{get<value_indices[I]>(meta_v<T>)...}; //
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  113 |          }(std::make_index_sequence<value_indices.size()>{}); //
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  114 |       }();
      |       ~~~
glaze-modularized/include/glaze/json/read.hpp:1787:49: note: in instantiation of template class 'glz::reflect<question_escaped_t>' requested here
 1787 |             static constexpr auto num_members = reflect<T>::size;
      |                                                 ^
glaze-modularized/include/glaze/json/read.hpp:74:40: note: in instantiation of function template specialization 'glz::detail::from<10, question_escaped_t>::op<opts{10, 1, 0, 1, 1, 1, 0, 0, 32, 3, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 32}, string_literal<1>{""}, question_escaped_t &, glz::context &, const char *&, const char *&>' requested here
   74 |                from<JSON, V>::template op<Opts>(std::forward<T>(value), std::forward<Ctx>(ctx), std::forward<It0>(it),
      |                                        ^
glaze-modularized/include/glaze/core/read.hpp:60:46: note: in instantiation of function template specialization 'glz::detail::read<10>::op<opts{10, 1, 0, 1, 1, 1, 0, 0, 32, 3, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 32}, question_escaped_t &, glz::context &, const char *&, const char *&>' requested here
   60 |          detail::read<Opts.format>::template op<is_padded_on<Opts>()>(value, ctx, it, end);
      |                                              ^
glaze-modularized/include/glaze/json/read.hpp:2742:14: note: in instantiation of function template specialization 'glz::read<opts{10, 1, 0, 1, 1, 1, 0, 0, 32, 3, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0}, question_escaped_t, std::basic_string<char> &, glz::context &>' requested here
 2742 |       return read<opts{}>(value, std::forward<Buffer>(buffer), ctx);
      |              ^
glaze-modularized/tests/json_test/json_test.cpp:4534:23: note: in instantiation of function template specialization 'glz::read_json<question_escaped_t, std::basic_string<char> &>' requested here
 4534 |       expect(not glz::read_json(obj, str));
      |                       ^
glaze-modularized/include/glaze/tuplet/tuple.hpp:435:14: note: initializer of 'meta_v<question_escaped_t>' is not a constant expression
  435 |       return static_cast<Tup&&>(tup)[tuplet::tag<I>()];
      |              ^
glaze-modularized/include/glaze/core/reflect.hpp:112:26: note: in call to 'get<1UL, const glz::tuple<const char *, std::basic_string<char> question_escaped_t::*, std::basic_string_view<char>, std::basic_string<char> question_escaped_t::*> &>(meta_v)'
  112 |             return tuple{get<value_indices[I]>(meta_v<T>)...}; //
      |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/core/reflect.hpp:111:17: note: in call to '[&]<size_t ...I>(std::index_sequence<I...>) {
    return tuple{get<value_indices[I]>(meta_v<question_escaped_t>)...};
}.operator()<0UL, 1UL>({})'
  111 |          return [&]<size_t... I>(std::index_sequence<I...>) { //
      |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  112 |             return tuple{get<value_indices[I]>(meta_v<T>)...}; //
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  113 |          }(std::make_index_sequence<value_indices.size()>{}); //
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/core/reflect.hpp:110:38: note: in call to '[] {
    return [&]<size_t ...I>(std::index_sequence<I...>) {
        return tuple{get<value_indices[I]>(meta_v<question_escaped_t>)...};
    }(std::make_index_sequence<value_indices.size()>{});
}.operator()()'
  110 |       static constexpr auto values = [] {
      |                                      ^~~~
  111 |          return [&]<size_t... I>(std::index_sequence<I...>) { //
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  112 |             return tuple{get<value_indices[I]>(meta_v<T>)...}; //
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  113 |          }(std::make_index_sequence<value_indices.size()>{}); //
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  114 |       }();
      |       ~~~
glaze-modularized/include/glaze/core/meta.hpp:143:26: note: declared here
  143 |    inline constexpr auto meta_v = []() -> decltype(auto) {
      |                          ^
In file included from glaze-modularized/tests/json_test/json_test.cpp:26:
In file included from glaze-modularized/include/glaze/api/impl.hpp:6:
In file included from glaze-modularized/include/glaze/api/api.hpp:13:
In file included from glaze-modularized/include/glaze/api/trait.hpp:11:
glaze-modularized/include/glaze/core/reflect.hpp:118:29: error: constexpr variable 'keys' must be initialized by a constant expression
  118 |       static constexpr auto keys = [] {
      |                             ^      ~~~~
  119 |          std::array<sv, size> res{};
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  120 |          [&]<size_t... I>(std::index_sequence<I...>) { //
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  121 |             ((res[I] = get_key_element<T, value_indices[I]>()), ...);
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  122 |          }(std::make_index_sequence<value_indices.size()>{});
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  123 |          return res;
      |          ~~~~~~~~~~~
  124 |       }();
      |       ~~~
glaze-modularized/include/glaze/tuplet/tuple.hpp:435:14: note: initializer of 'meta_v<question_escaped_t>' is not a constant expression
  435 |       return static_cast<Tup&&>(tup)[tuplet::tag<I>()];
      |              ^
glaze-modularized/include/glaze/core/reflect.hpp:75:17: note: in call to 'get<0UL, const glz::tuple<const char *, std::basic_string<char> question_escaped_t::*, std::basic_string_view<char>, std::basic_string<char> question_escaped_t::*> &>(meta_v)'
   75 |          return get<I - 1>(meta_v<V>);
      |                 ^~~~~~~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/core/reflect.hpp:121:24: note: in call to 'get_key_element<question_escaped_t, 1UL>()'
  121 |             ((res[I] = get_key_element<T, value_indices[I]>()), ...);
      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/core/reflect.hpp:120:10: note: in call to '[&]<size_t ...I>(std::index_sequence<I...>) {
    ((res[I] = get_key_element<question_escaped_t, value_indices[I]>()) , ...);
}.operator()<0UL, 1UL>({})'
  120 |          [&]<size_t... I>(std::index_sequence<I...>) { //
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  121 |             ((res[I] = get_key_element<T, value_indices[I]>()), ...);
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  122 |          }(std::make_index_sequence<value_indices.size()>{});
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/core/reflect.hpp:118:36: note: in call to '[] {
    std::array<sv, size> res{};
    [&]<size_t ...I>(std::index_sequence<I...>) {
        ((res[I] = get_key_element<question_escaped_t, value_indices[I]>()) , ...);
    }(std::make_index_sequence<value_indices.size()>{});
    return res;
}.operator()()'
  118 |       static constexpr auto keys = [] {
      |                                    ^~~~
  119 |          std::array<sv, size> res{};
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  120 |          [&]<size_t... I>(std::index_sequence<I...>) { //
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  121 |             ((res[I] = get_key_element<T, value_indices[I]>()), ...);
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  122 |          }(std::make_index_sequence<value_indices.size()>{});
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  123 |          return res;
      |          ~~~~~~~~~~~
  124 |       }();
      |       ~~~
glaze-modularized/include/glaze/core/meta.hpp:143:26: note: declared here
  143 |    inline constexpr auto meta_v = []() -> decltype(auto) {
      |                          ^
In file included from glaze-modularized/tests/json_test/json_test.cpp:26:
In file included from glaze-modularized/include/glaze/api/impl.hpp:6:
In file included from glaze-modularized/include/glaze/api/api.hpp:13:
In file included from glaze-modularized/include/glaze/api/trait.hpp:11:
glaze-modularized/include/glaze/core/reflect.hpp:118:36: error: call to immediate function 'glz::reflect<question_escaped_t>::(anonymous class)::operator()' is not a constant expression
  118 |       static constexpr auto keys = [] {
      |                                    ^
glaze-modularized/include/glaze/tuplet/tuple.hpp:435:14: note: initializer of 'meta_v<question_escaped_t>' is not a constant expression
  435 |       return static_cast<Tup&&>(tup)[tuplet::tag<I>()];
      |              ^
glaze-modularized/include/glaze/core/reflect.hpp:75:17: note: in call to 'get<0UL, const glz::tuple<const char *, std::basic_string<char> question_escaped_t::*, std::basic_string_view<char>, std::basic_string<char> question_escaped_t::*> &>(meta_v)'
   75 |          return get<I - 1>(meta_v<V>);
      |                 ^~~~~~~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/core/reflect.hpp:121:24: note: in call to 'get_key_element<question_escaped_t, 1UL>()'
  121 |             ((res[I] = get_key_element<T, value_indices[I]>()), ...);
      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/core/reflect.hpp:120:10: note: in call to '[&]<size_t ...I>(std::index_sequence<I...>) {
    ((res[I] = get_key_element<question_escaped_t, value_indices[I]>()) , ...);
}.operator()<0UL, 1UL>({})'
  120 |          [&]<size_t... I>(std::index_sequence<I...>) { //
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  121 |             ((res[I] = get_key_element<T, value_indices[I]>()), ...);
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  122 |          }(std::make_index_sequence<value_indices.size()>{});
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/core/reflect.hpp:118:36: note: in call to '[] {
    std::array<sv, size> res{};
    [&]<size_t ...I>(std::index_sequence<I...>) {
        ((res[I] = get_key_element<question_escaped_t, value_indices[I]>()) , ...);
    }(std::make_index_sequence<value_indices.size()>{});
    return res;
}.operator()()'
  118 |       static constexpr auto keys = [] {
      |                                    ^~~~
  119 |          std::array<sv, size> res{};
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  120 |          [&]<size_t... I>(std::index_sequence<I...>) { //
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  121 |             ((res[I] = get_key_element<T, value_indices[I]>()), ...);
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  122 |          }(std::make_index_sequence<value_indices.size()>{});
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  123 |          return res;
      |          ~~~~~~~~~~~
  124 |       }();
      |       ~~~
glaze-modularized/include/glaze/core/meta.hpp:143:26: note: declared here
  143 |    inline constexpr auto meta_v = []() -> decltype(auto) {
      |                          ^
In file included from glaze-modularized/tests/json_test/json_test.cpp:26:
In file included from glaze-modularized/include/glaze/api/impl.hpp:6:
In file included from glaze-modularized/include/glaze/api/api.hpp:13:
In file included from glaze-modularized/include/glaze/api/trait.hpp:11:
glaze-modularized/include/glaze/core/reflect.hpp:1286:19: error: constexpr variable 'keys_info<question_escaped_t>' must be initialized by a constant expression
 1286 |    constexpr auto keys_info = make_keys_info(reflect<T>::keys);
      |                   ^           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/core/reflect.hpp:1293:35: note: in instantiation of variable template specialization 'glz::detail::keys_info' requested here
 1293 |          constexpr auto& k_info = keys_info<T>;
      |                                   ^
glaze-modularized/include/glaze/core/reflect.hpp:1289:34: note: while substituting into a lambda expression here
 1289 |    constexpr auto hash_info = [] {
      |                                  ^
glaze-modularized/include/glaze/json/read.hpp:1913:41: note: in instantiation of variable template specialization 'glz::detail::hash_info' requested here
 1913 |                      static_assert(bool(hash_info<T>.type));
      |                                         ^
glaze-modularized/include/glaze/json/read.hpp:74:40: note: in instantiation of function template specialization 'glz::detail::from<10, question_escaped_t>::op<opts{10, 1, 0, 1, 1, 1, 0, 0, 32, 3, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 32}, string_literal<1>{""}, question_escaped_t &, glz::context &, const char *&, const char *&>' requested here
   74 |                from<JSON, V>::template op<Opts>(std::forward<T>(value), std::forward<Ctx>(ctx), std::forward<It0>(it),
      |                                        ^
glaze-modularized/include/glaze/core/read.hpp:60:46: note: in instantiation of function template specialization 'glz::detail::read<10>::op<opts{10, 1, 0, 1, 1, 1, 0, 0, 32, 3, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 32}, question_escaped_t &, glz::context &, const char *&, const char *&>' requested here
   60 |          detail::read<Opts.format>::template op<is_padded_on<Opts>()>(value, ctx, it, end);
      |                                              ^
glaze-modularized/include/glaze/json/read.hpp:2742:14: note: in instantiation of function template specialization 'glz::read<opts{10, 1, 0, 1, 1, 1, 0, 0, 32, 3, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0}, question_escaped_t, std::basic_string<char> &, glz::context &>' requested here
 2742 |       return read<opts{}>(value, std::forward<Buffer>(buffer), ctx);
      |              ^
glaze-modularized/tests/json_test/json_test.cpp:4534:23: note: in instantiation of function template specialization 'glz::read_json<question_escaped_t, std::basic_string<char> &>' requested here
 4534 |       expect(not glz::read_json(obj, str));
      |                       ^
glaze-modularized/include/glaze/core/reflect.hpp:1052:25: note: initializer of 'keys' is not a constant expression
 1052 |          const auto n = keys[i].size();
      |                         ^
glaze-modularized/include/glaze/core/reflect.hpp:1286:31: note: in call to 'make_keys_info<2UL>(keys)'
 1286 |    constexpr auto keys_info = make_keys_info(reflect<T>::keys);
      |                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/core/reflect.hpp:118:29: note: declared here
  118 |       static constexpr auto keys = [] {
      |                             ^
glaze-modularized/include/glaze/core/reflect.hpp:1299:24: error: constexpr if condition is not a constant expression
 1299 |          if constexpr (type == single_element) {
      |                        ^~~~~~~~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/core/reflect.hpp:1289:34: note: while substituting into a lambda expression here
 1289 |    constexpr auto hash_info = [] {
      |                                  ^
glaze-modularized/include/glaze/json/read.hpp:1913:41: note: in instantiation of variable template specialization 'glz::detail::hash_info' requested here
 1913 |                      static_assert(bool(hash_info<T>.type));
      |                                         ^
glaze-modularized/include/glaze/json/read.hpp:74:40: note: in instantiation of function template specialization 'glz::detail::from<10, question_escaped_t>::op<opts{10, 1, 0, 1, 1, 1, 0, 0, 32, 3, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 32}, string_literal<1>{""}, question_escaped_t &, glz::context &, const char *&, const char *&>' requested here
   74 |                from<JSON, V>::template op<Opts>(std::forward<T>(value), std::forward<Ctx>(ctx), std::forward<It0>(it),
      |                                        ^
glaze-modularized/include/glaze/core/read.hpp:60:46: note: in instantiation of function template specialization 'glz::detail::read<10>::op<opts{10, 1, 0, 1, 1, 1, 0, 0, 32, 3, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 32}, question_escaped_t &, glz::context &, const char *&, const char *&>' requested here
   60 |          detail::read<Opts.format>::template op<is_padded_on<Opts>()>(value, ctx, it, end);
      |                                              ^
glaze-modularized/include/glaze/json/read.hpp:2742:14: note: in instantiation of function template specialization 'glz::read<opts{10, 1, 0, 1, 1, 1, 0, 0, 32, 3, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0}, question_escaped_t, std::basic_string<char> &, glz::context &>' requested here
 2742 |       return read<opts{}>(value, std::forward<Buffer>(buffer), ctx);
      |              ^
glaze-modularized/tests/json_test/json_test.cpp:4534:23: note: in instantiation of function template specialization 'glz::read_json<question_escaped_t, std::basic_string<char> &>' requested here
 4534 |       expect(not glz::read_json(obj, str));
      |                       ^
glaze-modularized/include/glaze/core/reflect.hpp:1299:24: note: initializer of 'keys_info<question_escaped_t>' is not a constant expression
 1299 |          if constexpr (type == single_element) {
      |                        ^
glaze-modularized/include/glaze/core/reflect.hpp:1286:19: note: declared here
 1286 |    constexpr auto keys_info = make_keys_info(reflect<T>::keys);
      |                   ^
glaze-modularized/include/glaze/core/reflect.hpp:1305:29: error: constexpr if condition is not a constant expression
 1305 |          else if constexpr (type == mod4) {
      |                             ^~~~~~~~~~~~
glaze-modularized/include/glaze/core/reflect.hpp:1305:29: note: initializer of 'keys_info<question_escaped_t>' is not a constant expression
glaze-modularized/include/glaze/core/reflect.hpp:1286:19: note: declared here
 1286 |    constexpr auto keys_info = make_keys_info(reflect<T>::keys);
      |                   ^
glaze-modularized/include/glaze/core/reflect.hpp:1311:29: error: constexpr if condition is not a constant expression
 1311 |          else if constexpr (type == xor_mod4) {
      |                             ^~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/core/reflect.hpp:1311:29: note: initializer of 'keys_info<question_escaped_t>' is not a constant expression
glaze-modularized/include/glaze/core/reflect.hpp:1286:19: note: declared here
 1286 |    constexpr auto keys_info = make_keys_info(reflect<T>::keys);
      |                   ^
glaze-modularized/include/glaze/core/reflect.hpp:1317:29: error: constexpr if condition is not a constant expression
 1317 |          else if constexpr (type == minus_mod4) {
      |                             ^~~~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/core/reflect.hpp:1317:29: note: initializer of 'keys_info<question_escaped_t>' is not a constant expression
glaze-modularized/include/glaze/core/reflect.hpp:1286:19: note: declared here
 1286 |    constexpr auto keys_info = make_keys_info(reflect<T>::keys);
      |                   ^
glaze-modularized/include/glaze/core/reflect.hpp:1323:29: error: constexpr if condition is not a constant expression
 1323 |          else if constexpr (type == three_element_unique_index) {
      |                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/core/reflect.hpp:1323:29: note: initializer of 'keys_info<question_escaped_t>' is not a constant expression
glaze-modularized/include/glaze/core/reflect.hpp:1286:19: note: declared here
 1286 |    constexpr auto keys_info = make_keys_info(reflect<T>::keys);
      |                   ^
glaze-modularized/include/glaze/core/reflect.hpp:1331:29: error: constexpr if condition is not a constant expression
 1331 |          else if constexpr (type == front_hash) {
      |                             ^~~~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/core/reflect.hpp:1331:29: note: initializer of 'keys_info<question_escaped_t>' is not a constant expression
glaze-modularized/include/glaze/core/reflect.hpp:1286:19: note: declared here
 1286 |    constexpr auto keys_info = make_keys_info(reflect<T>::keys);
      |                   ^
glaze-modularized/include/glaze/core/reflect.hpp:1372:13: error: return type 'hash_info_t<[...], bsize aka 2>' must match previous return type 'hash_info_t<[...], bucket_size(single_element, N) aka 0>' when lambda expression has unspecified explicit return type
 1372 |             return info;
      |             ^
In file included from glaze-modularized/tests/json_test/json_test.cpp:26:
In file included from glaze-modularized/include/glaze/api/impl.hpp:24:
In file included from glaze-modularized/include/glaze/glaze.hpp:35:
In file included from glaze-modularized/include/glaze/beve.hpp:7:
In file included from glaze-modularized/include/glaze/beve/ptr.hpp:8:
In file included from glaze-modularized/include/glaze/core/ptr.hpp:9:
In file included from glaze-modularized/include/glaze/json/json_ptr.hpp:11:
glaze-modularized/include/glaze/json/read.hpp:1922:64: error: call to consteval function 'glz::detail::contains_tag<question_escaped_t, string_literal<1>{""}>' is not a constant expression
 1922 |                      if constexpr (not tag.sv().empty() && not contains_tag<T, tag>()) {
      |                                                                ^
glaze-modularized/include/glaze/json/read.hpp:74:40: note: in instantiation of function template specialization 'glz::detail::from<10, question_escaped_t>::op<opts{10, 1, 0, 1, 1, 1, 0, 0, 32, 3, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 32}, string_literal<1>{""}, question_escaped_t &, glz::context &, const char *&, const char *&>' requested here
   74 |                from<JSON, V>::template op<Opts>(std::forward<T>(value), std::forward<Ctx>(ctx), std::forward<It0>(it),
      |                                        ^
glaze-modularized/include/glaze/core/read.hpp:60:46: note: in instantiation of function template specialization 'glz::detail::read<10>::op<opts{10, 1, 0, 1, 1, 1, 0, 0, 32, 3, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 32}, question_escaped_t &, glz::context &, const char *&, const char *&>' requested here
   60 |          detail::read<Opts.format>::template op<is_padded_on<Opts>()>(value, ctx, it, end);
      |                                              ^
glaze-modularized/include/glaze/json/read.hpp:2742:14: note: in instantiation of function template specialization 'glz::read<opts{10, 1, 0, 1, 1, 1, 0, 0, 32, 3, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0}, question_escaped_t, std::basic_string<char> &, glz::context &>' requested here
 2742 |       return read<opts{}>(value, std::forward<Buffer>(buffer), ctx);
      |              ^
glaze-modularized/tests/json_test/json_test.cpp:4534:23: note: in instantiation of function template specialization 'glz::read_json<question_escaped_t, std::basic_string<char> &>' requested here
 4534 |       expect(not glz::read_json(obj, str));
      |                       ^
glaze-modularized/include/glaze/json/read.hpp:1772:38: note: initializer of 'keys' is not a constant expression
 1772 |          for (size_t i = 0; i < keys.size(); ++i) {
      |                                      ^
glaze-modularized/include/glaze/json/read.hpp:1922:64: note: in call to 'contains_tag<question_escaped_t, string_literal<1>{""}>()'
 1922 |                      if constexpr (not tag.sv().empty() && not contains_tag<T, tag>()) {
      |                                                                ^~~~~~~~~~~~~~~~~~~~~~
glaze-modularized/include/glaze/core/reflect.hpp:118:29: note: declared here
  118 |       static constexpr auto keys = [] {
      |                             ^
19 errors generated.

What did I miss here? Or is this an actual bug?

msqr1 avatar Feb 04 '25 03:02 msqr1

Also, are you sure you want to convert standard includes to import std/std.compat? It is not that well supported: https://en.cppreference.com/w/cpp/compiler_support#C.2B.2B23_library_features:~:text=Standard%20Library%20Modules

If you still insist, we can bootstrap it with a generated, fake std module. Or we can just still use standard includes in the GMF. @stephenberry

msqr1 avatar Feb 04 '25 03:02 msqr1

: note: assignment to member '_M_local_buf' of union with no active member is not allowed in a constant expression

short answer AFIR, gnu team in libstdc++ is allowed to break any c++ rules, clang team does not support breaking rules. so compiling constexpr clang + libstdc++ is tricky. I was bullied on the r/cpp for questioning libstdc++ std::string design.

arturbac avatar Feb 04 '25 09:02 arturbac

Also, are you sure you want to convert standard includes to import std/std.compat?

what's the point of that ? it does not change anything on user of glaze side. If it exists in system then it may speedup development of glaze when used but ... Do not expect that clang will be able to use libstdc++ g++ build modules.

arturbac avatar Feb 04 '25 09:02 arturbac

To get more out of the compile time benefits of modules using import std/std.compat gives better performance in my experience. But, if the support isn't there I'm okay with an approach that uses #include. I haven't done enough testing to understand the current differences in support between approaches (especially with Clang), but I found with MSVC import std/std.compat was much more stable than trying to mix modules and #include.

stephenberry avatar Feb 04 '25 14:02 stephenberry

@msqr1 Your Clang compilation error is probably because you need to build with -stdlib=libc++. Using the default GCC implementation currently has compile time bugs.

stephenberry avatar Feb 04 '25 14:02 stephenberry

Thanks for all the helpful thoughts and notes here. I've done some module experimentation and was waiting for better GCC support before continuing, but I am eager to see what others are able to acheive.

Some thoughts:

  • When moving Glaze to C++20 modules I want to move to pure modules. Glaze only depends on the standard library, so there is no need for an intermediate approach that mixes headers and modules. Glaze will still need to be used with a header include approach, but if the user wants Glaze as a module, #include should not exist within the Glaze module. This means that import std must be supported for any compiler that we want to use for modular Glaze. We are waiting on GCC 15 for import std. But, I would be happy getting modules with Glaze just working on Clang for now.

A big +1 to this. It will be best to support pure modules if possible. The export-and-using style is actually a wrapper only. And also it will be best to use import std; whenever possible.

  • Using macros to conditionally create a module in C++ is not valid and MSVC will issue warnings. So, I think the current approach of importizer is incorrect (@msqr1 do you not see these warnings with MSVC?).

ChuanqiXu9 avatar Feb 05 '25 08:02 ChuanqiXu9