1

Is it possible to extract the parameter type from a template type?

For example:

using T = std::vector<int>;
using P = parameter_type<T>::type; // U should be int

Or, it could be more complex:

using T = std::map<int, std::vector<std::string>>;
using P1 = parameter_type<T, 1>::type; // P1 should be int
using P2 = parameter_type<T, 2>::type; // P2 should b std::vector<std::string>
fatdragon
  • 2,211
  • 4
  • 26
  • 43
  • 1
    For a vector it will be value_type, e.g. `using T = typename std::vector::value_type` see https://en.cppreference.com/w/cpp/container/vector section 'member types'. – Pepijn Kramer Jul 23 '22 at 17:32
  • Do you want to get the `value_type` of a standard container or just get the type(s) upon which a template is parametrized? – paolo Jul 23 '22 at 17:37
  • 1
    1. `T::value_type` 2. `T::key_type` and `T::mapped_type`. – 康桓瑋 Jul 23 '22 at 17:38
  • You seem to be asking two different questions. One (in the title) is how to access the types which a container is using, which is somewhat specific to the container in question, see comments above. The other is how to extract template arguments from a type, independently of whether the type is a container, which seems to be what the body of your question is asking. Which one is it? – user17732522 Jul 23 '22 at 17:40
  • Sorry about the confusion. I started writing "container" but then I realize that my current challenge is not container but rather some other complex types. – fatdragon Jul 23 '22 at 17:54

1 Answers1

2

Do you want it to work for containers or fully generic solution? STL containers have special members documenting their "kinds". Vector has ::value_type, map has key_type and mapped_type.

The following might be able to extra generic template arguments:

#include <tuple>

template <typename T> struct parameter_type_impl;

template <template <class...> class T, typename... Args>
struct parameter_type_impl<T<Args...>> {
    using type = std::tuple<Args...>;
};

// Using the sane zero-based indexing.
template <typename T, std::size_t I = 0>
using parameter_type =
    std::tuple_element<I, typename parameter_type_impl<T>::type>;

template <typename T, std::size_t I = 0>
using parameter_type_t = typename parameter_type<T, I>::type;
#include <map>
#include <vector>

int main() {

    using v1 = parameter_type_t<std::vector<int>>;
    static_assert(std::is_same_v<v1, int>);
    using v2 = parameter_type_t<std::map<int, float>>;
    static_assert(std::is_same_v<v2, int>);
    using v3 = parameter_type_t<std::map<int, float>, 1>;
    static_assert(std::is_same_v<v3, float>);
}

I am not quite sure whether there are any edge cases which won't match the variadic specialization so your mileage might vary.

Quimby
  • 17,735
  • 4
  • 35
  • 55
  • 2
    Any class template that has a non-type parameter won't match; e.g. `std::array`. – paolo Jul 23 '22 at 17:49
  • Thanks. I actually want to work with a custom solution - in particular, involving, folly::Future, folly::Task, and folly::Function. – fatdragon Jul 23 '22 at 17:53
  • @fatdragon There is no generic template reflection in C++ unfortunately, but give this a go, as paolo said, it won't work if the template contains non-type parameters, as [there is no way how to match on it](https://stackoverflow.com/questions/39812789/is-there-any-way-of-detecting-arbitrary-template-classes-that-mix-types-and-non). – Quimby Jul 23 '22 at 17:58