275.md

September 5, 2022 ยท View on GitHub

Info

Example

template <std::size_t N> struct fixed_string final {
  constexpr explicit(false) fixed_string(const char (&str)[N + 1]) {
    std::copy_n(str, N + 1, std::data(data));
  }

  [[nodiscard]] constexpr auto operator<=>(const fixed_string &) const = default;

  std::array<char, N + 1> data{};
};

template <std::size_t N>
fixed_string(const char (&str)[N]) -> fixed_string<N - 1>;

template<fixed_string> struct foo;

int main() {
  what_is_my_type<"Quantlab">{}; // clang: 'what_is_my_type<{{"Quantlab"}}>'
                                 // gcc: struct what_is_my_type<fixed_string<8>{std::array<char, 9>{"Quantlab"}}>
}

https://godbolt.org/z/fqWo5nvTa

Puzzle

  • Can you implement to_string_t which converts fixed_string into string<char...>?
template <char... Cs> struct string {};
template <class T, T... Cs> [[nodiscard]] constexpr auto operator""_cs() { return string<Cs...>{}; }

template <std::size_t N>
struct fixed_string; // TODO

template <fixed_string Str>
using to_string_t; // TODO

static_assert(std::is_same_v<decltype(""_cs), to_string_t<"">>);
static_assert(std::is_same_v<decltype("Q"_cs), to_string_t<"Q">>);
static_assert(std::is_same_v<decltype("Foo"_cs), to_string_t<"Foo">>);
static_assert(std::is_same_v<decltype("Bar"_cs), to_string_t<"Bar">>);
static_assert(not std::is_same_v<decltype("fo"_cs), to_string_t<"foo">>);
static_assert(not std::is_same_v<decltype("foo"_cs), to_string_t<"Foo">>);
static_assert(not std::is_same_v<decltype("Foo"_cs), to_string_t<"Bar">>);
static_assert(not std::is_same_v<decltype("Bar"_cs), to_string_t<"Foo">>);

https://godbolt.org/z/adT4rfEbh

Solutions

template <std::size_t N>
struct fixed_string final {
    constexpr explicit(false) fixed_string(const char (&str)[N + 1]) {
        std::copy_n(str, N + 1, std::data(data));
    }

    [[nodiscard]] constexpr auto
    operator<=>(const fixed_string &) const = default;

    std::array<char, N + 1> data{};
};

template <std::size_t N>
fixed_string(const char (&str)[N]) -> fixed_string<N - 1>;

template <fixed_string Str>
using to_string_t = decltype([]<std::size_t... Is>(std::index_sequence<Is...>) {
    return string<Str.data[Is]...>{};
}(std::make_index_sequence<Str.data.size() - 1>()))

https://godbolt.org/z/fo4dz7Y8e

#define FWD(...) static_cast<decltype(__VA_ARGS__)&&>(__VA_ARGS__)

namespace detail {

template <auto Container, auto... Is>
[[nodiscard]] consteval decltype(auto) apply_impl(auto&& func,
                                                  std::index_sequence<Is...>) {
    return func.template operator()<Container[Is]...>();
}

template <auto Container>
[[nodiscard]] consteval decltype(auto) apply(auto&& func) {
    return detail::apply_impl<Container>(
        FWD(func), std::make_index_sequence<std::size(Container)>{});
}

}  // namespace detail

template <char... Cs>
struct string {};

template <class T, T... Cs>
[[nodiscard]] constexpr auto operator""_cs() {
    return string<Cs...>{};
}

template <std::size_t N>
struct fixed_string {
    constexpr explicit(false) fixed_string(const char (&str)[N + 1]) {
        std::copy_n(str, N, std::data(chars));
    }

    std::array<char, N> chars;
};
template <std::size_t N>
fixed_string(const char (&str)[N]) -> fixed_string<N - 1>;

template <fixed_string Str>
using to_string_t = decltype(detail::apply<Str.chars>(
    []<char... Cs>() { return string<Cs...>{}; }));

https://godbolt.org/z/d5rbc5Wch

template <fixed_string Str>
using to_string_t = decltype([]<auto... Is>(std::index_sequence<Is...>) {
  return string<Str[Is]...>{};
}(std::make_index_sequence<std::size(Str) - 1>{}));

https://godbolt.org/z/11rcY9nGb