2

The following lambda is supposed to return the string formatter for printf and alike at compiletime, however it doesn't seem to work as intended and I can't get behind it.

Demo

#include <array>
#include <string_view>
#include <iostream>

int main() {
    using T = unsigned char;
    constexpr std::string_view fmt = [&]() -> std::string_view {
        std::tuple<char, unsigned char, short, unsigned short, int,
            unsigned int, long, unsigned long, long long, unsigned long long> dummy;
        constexpr std::size_t map_size = std::tuple_size_v<decltype(dummy)>;
        constexpr std::size_t idx = [&]<std::size_t... Is>(std::index_sequence<Is...>){
            std::size_t ret = 0;
            ([&]{ ret = Is; return std::same_as<T, decltype(std::get<Is>(dummy))>; }() || ...);
            return ret;
        }(std::make_index_sequence<map_size>{});
        return std::array<std::string_view, map_size>{ "%hhd", "%hhu", "%hd", "%hu", "%d", "%u", "%ld", "%lu", "%lld", "%llu" }[idx];
    }();
    std::cout << fmt << std::endl;
}

Currently it outputs:

%llu

Expected result:

%hhu
glades
  • 3,778
  • 1
  • 12
  • 34

1 Answers1

4

decltype(std::get<Is>(dummy)) is T& for a mutable std::tuple, const T& for immutable std::tuple. Use std::tuple_element_t instead:

            ([&]{ ret = Is; return std::same_as<T, std::tuple_element_t<Is, decltype(dummy)>>; }() || ...);
yeputons
  • 8,478
  • 34
  • 67
  • yep, that was it. I don't quite understand what the difference is though, since std::get returns a tuple_element as well :/ EDIT: Ahh I get it, it's about the reference. I would have to clear it from cvref first. – glades Jun 29 '23 at 08:03
  • 1
    `using types = std::tuple<..>` might replace `dummy` too [Demo](https://godbolt.org/z/cv433cPzh). – Jarod42 Jun 29 '23 at 13:38