Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type trait that returns the template parameter of a template function

Suppose one has the following template function:

template<typename T>  auto foobar ()  { return std::string("why not"); }

Question: is it possible to define a type trait that provides the template parameter of the function ?

If we call get_template_parameter such a trait, one could then write:

template<typename T>  auto foobar ()  { return std::string("why not"); }

using type = typename get_template_parameter <decltype(foobar<double>)>::type;

static_assert (std::is_same_v<type,double>);

UPDATE: I added a dummy result to the foobar function in order to underline the fact that the template parameter is not related to the result of the function.

like image 762
abcdefg Avatar asked Oct 31 '25 10:10

abcdefg


1 Answers

An other option, less intrusive than making the function a functor or returning a pair, would be to add the templated type T as the last argument of the function with a default argument, allowing the function to be called with the same signature than before.

Then the type can be determined, by looking at decltype(foobar<double>) and extracting the last argument as presented here.

template<typename T>
struct tag
{
    using type = T;
};

template<typename... Ts>
struct select_last
{
    // Use a fold-expression to fold the comma operator over the parameter pack.
    using type = typename decltype((tag<Ts>{}, ...))::type;
};

template<typename T>
struct get_template_parameter;

template<typename R, typename... T>
struct get_template_parameter<R(T...)> : select_last<T...> {
};

template<typename T>
using get_template_parameter_t = typename get_template_parameter<T>::type;

template <typename T>
auto foobar([[maybe_unused]] T t = {}) {
    return std::string();
}


int main() {
    static_assert(std::is_same_v<double, get_template_parameter_t<decltype(foobar<double>)>>);
}

Note that this can be problematic, if T is somehow not easy to construct. Then an option would be to make the last argument a reference of T and letting the tag remove the reference again:

template<typename T>
struct tag
{
    using type = std::remove_reference_t<T>;
};

/* code as before ... */

template <typename T>
auto func([[maybe_unused]] T& t = {}) {
    return std::string();
}
like image 168
0xbachmann Avatar answered Nov 02 '25 00:11

0xbachmann



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!