Is there a simple way to implement a function like this
template <typename Tuple, typename... Args>
constexpr auto make_similar_tuple(Args&&... args);
that casts its arguments to a given tuple element types preserving CV qualifiers and references and returns a tuple of that arguments.
so that
using Tuple = std::tuple<std::string, int>;
make_similar_tuple<Tuple, std::string, int> returns std::tuple<std::string, int>
make_similar_tuple<Tuple, std::string&, int> returns std::tuple<std::string&, int>
make_similar_tuple<Tuple, std::string&, int8_t> returns std::tuple<std::string&, int>
make_similar_tuple<Tuple, const char*, int8_t> returns std::tuple<std::string, int>
make_similar_tuple<Tuple, const std::string&, int> returns std::tuple<const std::string&, int>
An example of a user code:
using Tuple = std::tuple<std::string, int>;
int i = 10;
auto t = make_similar_tuple<Tuple>("a", i);
static_assert(std::is_same_v<decltype(t), std::tuple<std::string, int&>>);
assert(t == std::make_tuple(std::string("a"), 10));
The implementation should cast "a"
to std::string
as in the code below:
#include <iostream>
int main()
{
auto a = static_cast<std::string>("a");
std::cout << a << std::endl;
return 0;
}
but the second element remains the reference becuase i
is lvalue
.
It seems that you can get the corresponding type of the returned tuple
through common_reference_t<T&, Args>
#include <tuple>
template <typename Tuple, typename... Args>
constexpr auto
make_similar_tuple(Args&&... args) {
static_assert(std::tuple_size_v<Tuple> == sizeof...(Args));
return [&]<size_t... Is>(std::index_sequence<Is...>) {
return std::tuple<
std::common_reference_t<
std::tuple_element_t<Is, Tuple>&, Args
>...
>(std::forward<Args>(args)...);
}(std::index_sequence_for<Args...>{});
}
Demo with your testcases