Pewnie, możesz sobie dispatchować po wartości, którą uzyskasz sprawdzając wymagane warunki (w przykładzie: is_trivial + rozmiar odpowiednio mały):
namespace detail {
template<typename T>
constexpr static bool use_value = std::is_trivial_v<T> &&
(sizeof(T) <= sizeof(void*));
template<typename T, bool> struct param_type;
template<typename T> struct param_type<T, true>{ using type = T; };
template<typename T> struct param_type<T, false>{ using type = T&; };
} // namespace detail
A następnie
template<typename T> using param_type =
detail::param_type<T, detail::use_value<T>>::type;
Lub jeszcze prościej, z conditional_t
:
namespace detail
{
template<typename T>
constexpr static bool use_value = std::is_trivial_v<T> &&
(sizeof(T) <= sizeof(void*));
}
template<typename T> using param_type =
std::conditional_t<detail::use_value<T>, T, T&>;
W obu przypadkach:
template<typename T>
struct test
{
void foo(param_type<T>) const
{
BARK;
}
};
struct too_big{ int arr[10]; };
int main()
{
test<int> t1;
test<too_big> t2;
int i{};
too_big tb{};
t1.foo(i);
t2.foo(tb);
}
https://wandbox.org/permlink/70Zp4tHVM2F45jwk
19 void test<T>::foo(param_type<T>) const [with T = int; param_type<T> = int]
19 void test<T>::foo(param_type<T>) const [with T = too_big; param_type<T> = too_big&]