c++rangefmtc++23

How can we use std::tuple in conjunction with ranges


The problem I got is I have a function that takes a variadic argument. I want to use this for fmt printing . The way I am trying to achieve this is by joining them.

I have my join function:

template <typename RANGE, typename Projection = std::identity>
inline auto join(const RANGE& range, std::string_view sep, Projection&& proj = std::identity{}) {
    auto joined = range
        | std::views::transform([&proj](const auto& element) { return std::invoke(proj, element); })
        | std::views::join_with(sep);
    return std::ranges::to<std::string>(joined);
}

for now ignore std::invoke as it is simply deducing to the identity i.e. std::format("{}");

If I supply a vector it works fine, however, if I got a variadic function like:

template<Args..>
foo(Args... args) {
       std::string goo = std::format(
        "Show me the keys: {}",
        join(args..., ",")
    );
}

It does not work. I also tried with std::forward_as_tuple to cast my args to a std::tuple, however, that did not help since operand | is not supported by std::tuple.

I have an example here showing the case with a std::vector and std::tuple (in conjunction with variadic arguments)

The whole example is pasted below:

#include <iostream>
#include <string>
#include <vector>
#include <ranges>
#include <format>
#include <functional>

    

template <typename RANGE, typename Projection = std::identity>
inline auto join(const RANGE& range, std::string_view sep, Projection&& proj = std::identity{}) {
    auto joined = range
        | std::views::transform([&proj](const auto& element) { return std::invoke(proj, element); })
        | std::views::join_with(sep);
    return std::ranges::to<std::string>(joined);
}

template<typename... KEYS>
auto get(KEYS... keys) {
    return std::forward_as_tuple(std::forward<KEYS>(keys)...);
}

int main() {
    auto tuple_range = get("bla", "blas", "blaaaass");
    auto vv = std::vector<std::string>{"bla", "blas", "blaass"};
    std::string goo = std::format(
        "Show me the keys: {}",
        join(vv, ",")
    );
    std::cout << goo << std::endl;
    return 0;
}

Solution

  • Tuples aren't ranges. A range, in C++ terms, requires that all elements of the range are of the same type. Tuples aren't like that, so they cannot be manipulated by any range mechanisms.