Added etl::forward_like

This commit is contained in:
John Wellbelove 2023-07-15 09:51:08 +01:00
parent 5977555f3b
commit 73c96a4c6c
2 changed files with 282 additions and 1 deletions

View File

@ -68,6 +68,55 @@ namespace etl
ETL_STATIC_ASSERT(!etl::is_lvalue_reference<T>::value, "Invalid rvalue to lvalue conversion");
return static_cast<T&&>(t);
}
//******************************************************************************
/// See std::forward_like https://en.cppreference.com/w/cpp/utility/forward_like
/// Returns a reference to x which has similar properties to T&&.
///\return
/// If etl::remove_reference_t<T> is const then returns a const reference if U is an lvalue, otherwise a const rvalue reference.
/// If etl::remove_reference_t<T> is not const then returns a reference if U is an lvalue, otherwise an rvalue reference.
//******************************************************************************
template <typename T, typename U>
ETL_NODISCARD
ETL_CONSTEXPR14
auto&& forward_like(U&& u) ETL_NOEXCEPT
{
using TType = etl::remove_reference_t<T>;
using UType = etl::remove_reference_t<U>;
if ETL_IF_CONSTEXPR (etl::is_const<TType>::value)
{
// For const TType
if ETL_IF_CONSTEXPR (etl::is_lvalue_reference<T>::value)
{
// const lvalue
return static_cast<const UType&>(u);
}
else
{
// const rvalue
return static_cast<const UType&&>(u);
}
}
else
{
// For non-const TType
if ETL_IF_CONSTEXPR (etl::is_lvalue_reference<T>::value)
{
// lvalue
return static_cast<UType&>(u);
}
else
{
// rvalue
return static_cast<UType&&>(u);
}
}
}
// Defines the type that forward_like would cast to.
template <typename T, typename U>
using forward_like_t = decltype(etl::forward_like<T>(etl::declval<U&>()));
#endif
// We can't have std::swap and etl::swap templates coexisting in the unit tests
@ -612,4 +661,3 @@ namespace etl
}
#endif

View File

@ -432,5 +432,238 @@ namespace
CHECK_EQUAL(2, pf(1));
}
//*************************************************************************
struct SF
{
};
//*********************************
enum class forward_call_type
{
LValue,
ConstLValue,
RValue,
ConstRValue
};
//*********************************
std::ostream& operator << (std::ostream& os, forward_call_type type)
{
switch (type)
{
case forward_call_type::LValue:
{
os << "LValue";
break;
}
case forward_call_type::ConstLValue:
{
os << "ConstLValue";
break;
}
case forward_call_type::RValue:
{
os << "RValue";
break;
}
case forward_call_type::ConstRValue:
{
os << "ConstRValue";
break;
}
default:
{
os << "Unknown type";
break;
}
}
return os;
}
//*********************************
forward_call_type function_f(SF&)
{
return forward_call_type::LValue;
}
//*********************************
forward_call_type function_f(const SF&)
{
return forward_call_type::ConstLValue;
}
//*********************************
forward_call_type function_f(SF&&)
{
return forward_call_type::RValue;
}
//*********************************
forward_call_type function_f(const SF&&)
{
return forward_call_type::ConstRValue;
}
//*********************************
template <typename T>
forward_call_type template_function_f(T&& t)
{
return function_f(etl::forward<T>(t));
}
//*********************************
TEST(test_forward)
{
SF s1;
const SF s2;
CHECK_EQUAL(forward_call_type::LValue, template_function_f(s1));
CHECK_EQUAL(forward_call_type::RValue, template_function_f(etl::move(s1)));
CHECK_EQUAL(forward_call_type::ConstLValue, template_function_f(s2));
CHECK_EQUAL(forward_call_type::ConstRValue, template_function_f(etl::move(s2)));
}
//*************************************************************************
struct TFL
{
};
struct UFL
{
};
enum class forward_like_call_type
{
LValue,
ConstLValue,
RValue,
ConstRValue
};
//*********************************
std::ostream& operator << (std::ostream& os, forward_like_call_type type)
{
switch (type)
{
case forward_like_call_type::LValue:
{
os << "LValue";
break;
}
case forward_like_call_type::ConstLValue:
{
os << "ConstLValue";
break;
}
case forward_like_call_type::RValue:
{
os << "RValue";
break;
}
case forward_like_call_type::ConstRValue:
{
os << "ConstRValue";
break;
}
default:
{
os << "Unknown type";
break;
}
}
return os;
}
//*********************************
forward_like_call_type function_fl(UFL&)
{
return forward_like_call_type::LValue;
}
//*********************************
forward_like_call_type function_fl(const UFL&)
{
return forward_like_call_type::ConstLValue;
}
//*********************************
forward_like_call_type function_fl(UFL&&)
{
return forward_like_call_type::RValue;
}
//*********************************
forward_like_call_type function_fl(const UFL&&)
{
return forward_like_call_type::ConstRValue;
}
//*********************************
template <typename T, typename U>
forward_like_call_type template_function_fl(U&& u)
{
return function_fl(etl::forward_like<T>(u));
}
//*********************************
TEST(test_forward_like)
{
UFL u1;
const UFL u2;
UFL& u3 = u1;
const UFL& u4 = u2;
CHECK_EQUAL(forward_like_call_type::LValue, template_function_fl<TFL&>(u1));
CHECK_EQUAL(forward_like_call_type::ConstLValue, template_function_fl<const TFL&>(u1));
CHECK_EQUAL(forward_like_call_type::RValue, template_function_fl<TFL&&>(u1));
CHECK_EQUAL(forward_like_call_type::ConstRValue, template_function_fl<const TFL&&>(u1));
CHECK_EQUAL(forward_like_call_type::LValue, template_function_fl<TFL&>(etl::move(u1)));
CHECK_EQUAL(forward_like_call_type::ConstLValue, template_function_fl<const TFL&>(etl::move(u1)));
CHECK_EQUAL(forward_like_call_type::RValue, template_function_fl<TFL&&>(etl::move(u1)));
CHECK_EQUAL(forward_like_call_type::ConstRValue, template_function_fl<const TFL&&>(etl::move(u1)));
CHECK_EQUAL(forward_like_call_type::ConstLValue, template_function_fl<TFL&>(u2));
CHECK_EQUAL(forward_like_call_type::ConstLValue, template_function_fl<const TFL&>(u2));
CHECK_EQUAL(forward_like_call_type::ConstRValue, template_function_fl<TFL&&>(u2));
CHECK_EQUAL(forward_like_call_type::ConstRValue, template_function_fl<const TFL&&>(u2));
CHECK_EQUAL(forward_like_call_type::ConstLValue, template_function_fl<TFL&>(etl::move(u2)));
CHECK_EQUAL(forward_like_call_type::ConstLValue, template_function_fl<const TFL&>(etl::move(u2)));
CHECK_EQUAL(forward_like_call_type::ConstRValue, template_function_fl<TFL&&>(etl::move(u2)));
CHECK_EQUAL(forward_like_call_type::ConstRValue, template_function_fl<const TFL&&>(etl::move(u2)));
CHECK_EQUAL(forward_like_call_type::LValue, template_function_fl<TFL&>(u3));
CHECK_EQUAL(forward_like_call_type::ConstLValue, template_function_fl<const TFL&>(u3));
CHECK_EQUAL(forward_like_call_type::RValue, template_function_fl<TFL&&>(u3));
CHECK_EQUAL(forward_like_call_type::ConstRValue, template_function_fl<const TFL&&>(u3));
CHECK_EQUAL(forward_like_call_type::LValue, template_function_fl<TFL&>(etl::move(u3)));
CHECK_EQUAL(forward_like_call_type::ConstLValue, template_function_fl<const TFL&>(etl::move(u3)));
CHECK_EQUAL(forward_like_call_type::RValue, template_function_fl<TFL&&>(etl::move(u3)));
CHECK_EQUAL(forward_like_call_type::ConstRValue, template_function_fl<const TFL&&>(etl::move(u3)));
CHECK_EQUAL(forward_like_call_type::ConstLValue, template_function_fl<TFL&>(u4));
CHECK_EQUAL(forward_like_call_type::ConstLValue, template_function_fl<const TFL&>(u4));
CHECK_EQUAL(forward_like_call_type::ConstRValue, template_function_fl<TFL&&>(u4));
CHECK_EQUAL(forward_like_call_type::ConstRValue, template_function_fl<const TFL&&>(u4));
CHECK_EQUAL(forward_like_call_type::ConstLValue, template_function_fl<TFL&>(etl::move(u4)));
CHECK_EQUAL(forward_like_call_type::ConstLValue, template_function_fl<const TFL&>(etl::move(u4)));
CHECK_EQUAL(forward_like_call_type::ConstRValue, template_function_fl<TFL&&>(etl::move(u4)));
CHECK_EQUAL(forward_like_call_type::ConstRValue, template_function_fl<const TFL&&>(etl::move(u4)));
}
};
}