Search code examples
c++lambdatemplate-meta-programmingstdtuple

Retrieving printf format parameter by type


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

Solution

  • 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)>>; }() || ...);