As the title says. C++ already has std::forward, but it can't cast the original type to another. I wonder if there is a function to cast one type to another while preserving the value category and cv-qualifers of the original type.
Supposing there is such a function called perfect_cast to do the magic, the output of the following code
#include <iostream>
#include <type_traits>
#include <format>
template <typename To, typename From>
decltype(auto) perfect_cast(From&& s)
{
// ???
}
template <std::size_t I>
struct A
{
void f()&
{
std::cout << std::format("lvalue A{:d}", I) << std::endl;
}
void f() const&
{
std::cout << std::format("const lvalue A{:d}", I) << std::endl;
}
void f()&&
{
std::cout << std::format("rvalue A{:d}", I) << std::endl;
}
void f() const&&
{
std::cout << std::format("const rvalue A{:d}", I) << std::endl;
}
};
template <std::size_t ...Is>
struct B : A<Is>... {};
auto g1()
{
return B<0, 1, 2, 3>{};
}
const auto g2()
{
return B<0, 1, 2, 3>{};
}
int main()
{
B<0, 1, 2, 3> b;
auto& b1 = b;
perfect_cast<A<0>>(b1).f();
const auto& b2 = b1;
perfect_cast<A<1>>(b2).f();
perfect_cast<A<2>>(g1()).f();
perfect_cast<A<3>>(g2()).f();
}
should be
lvalue A0
const lvalue A1
rvalue A2
const rvalue A3
There aren't a lot of use cases for a combined conversion-forward. Arguably, most casts result in prvalues, and for derived-to-base casts, the language already permits treating the derived as base, preserving value category.
For example, the OP main would be more clearly written as:
B<0, 1, 2, 3> b;
auto& b1 = b;
b1.A<0>::f();
const auto& b2 = b1;
b2.A<1>::f();
g1().A<2>::f();
g2().A<3>::f();
See https://godbolt.org/z/Kff9zKPha
Perhaps it is useful to know there is a seemingly related problem of forwarding an object x in the manner of some other object y. This is useful (say, if x is "part" of y). That is useful enough that it was standardized as std::forward_like. (It is more complex than it should have to be, because of some past poor language design decisions.)