I came across an interesting constexpr problem that haven't been able to fully crack. The last piece of the puzzle that I'm missing is the following
// Given a constexpr array of string views
constexpr std::array<std::string_view, X> views = ...;
// Convert it to a list of char arrays
constexpr std::tuple<std::array<char, Xs>...> buffers = ...;
My problem here is finding the right size for each array. How can I extract the sizes of the string_views in views and pass them as template parameters to another function?
I could just use the same size for every buffer, big enough to hold every argument, but I'm wondering if there is a way of optimizing their sizes since the info is known at compile time.
Full description of the problem I'm trying to solve. (in case someone can come up with a better approach, also cause I think it's interesting...)
I want to create a macro that converts a list of arguments into a list of name-value pairs. For instance
// Adding types explicitly to show what I want to achieve.
int x;
float y;
double z;
using named_values_t = std::tuple<
std::pair<const char*, int&>,
std::pair<const char*, float&>,
std::pair<const char*, double&>>;
named_values_t nv = MY_MACRO(x, y, z);
The const char* adds significant difficulty but it's a requirement for a third-party lib.
Now I know that can be done with Boost.Preprocessor but I'd like to do it just using the STL and constexpr methods to avoid adding boost just for this. Also I know this would be trivial on a compiler with support for constexpr std::string but I'm using C++17.
The string processing can be easily done with constexpr functions,
// Split "one, two, three" into {"one", "two", "three"}.
template <size_t Count>
constexpr std::array<std::string_view, Count> split_arguments(std::string_view);
However, I cannot pass these string_views directly as char pointers, since at this point they're just pointers to a bigger array in memory (the complete "one, two, three"). To pass as const char* each element needs to be null-terminated.
But we can build an std::array for each std::string_view and copy its contents, this way we have a char array for each argument name, that will generate a null-terminated segment of memory for each name.
constexpr std::string_view args = "one, two, three";
constexpr std::array<std::string_view, 3> views = split_arguments<3>(args); // {"one", "two", "three"}
constexpr std::tuple<std::array<char, Xs>...> buffers = make_buffers<Xs...>(views);
Here I'm not able to figure out how pass the lengths of the views as template arguments to the next function.
Working solution here (using bigger fixed-sized buffers): https://gcc.godbolt.org/z/WKsbvb
The fixed-size buffer solution is ok, but it would be great to go that extra step to fit the buffers to their actual size.