Reputation: 663
I am working on a compile-time wrapper library and stumbled upon a problem of extracting a template parameter type from a given type.
The situation is the following. I have an unchangeable class R
:
template <class T>
class R {};
I also have an unchangeable main
function:
int main()
{
auto r = new R<int>();
// Function that knows the type of 'r'
create_obj<decltype(r)>();
delete r;
return 0;
}
The create_obj
function is the one that I am working on. For visualization purposes, I will write it the following way:
template< class C >
void create_obj()
{
// Print the type of the function (Output: R<int>*)
std::cout << boost::typeindex::type_id<C>().pretty_name() << std::endl;
}
And the problem is that I need to access the int
template parameter type of the R
class from the create_obj
function.
Pseudocode:
template<
template < class T >
class C<T>
>
void create_obj()
{
// Print the type of the function (Output: int)
std::cout << boost::typeindex::type_id<T>().pretty_name() << std::endl;
}
Is it possible to do it? I was going through the C++ documentation but I was not able to find any way to "detach" the template parameter type from the class definition.
Upvotes: 1
Views: 91
Reputation: 66200
I instead calling create_obj()
through the type of r
create_obj<decltype(r)>();
you can call it passing directly r
, the solution is simple
template <typename T>
void create_obj (R<T> const *)
{ /* do something with T */ }
But if you want call create_obj()
passing only the type R<T>
(or a type pointer to R<T>
) without instantiating an object of type R<T>
, you can define a lightweight type wrapper
template <typename>
struct typeWrapper
{ /* empty! */ };
redefine create_obj()
receiving a typeWrapper
of a R<T>
pointer
template <typename T>
void create_obj (typeWrapper<R<T> *> const &)
{ /* do something with T */ }
and call it using decltype(r)
create_obj(typeWrapper<decltype(r)>{});
or directly R<int> *
create_obj(typeWrapper<R<int> *>{});
Another alternative is declare create_obj
as a struct/class
template <typename>
struct create_obj;
and define only a specialization based on a R<T> *
pointer, with a static
func()
method in it
template <typename T>
struct create_obj<R<T> *>
{
static void func ()
{ /* do something with T */ }
};
You can use it through decltype(r)
create_obj<decltype(r)>::func();
or through R<int> *
create_obj<R<int> *>::func();
If you prefer, instead of a static
func()
method, you can insert in create_obj()
an ordinary (non static
) method; maybe an operator()
. But, this way, you have to instantiate a create_obj
object to call the method.
Upvotes: 0
Reputation: 19113
Yes, it is possible, one way to do it:
template<typename T>
class R{};
template<typename C>
struct extract_impl{};
template<typename T>
struct extract_impl<R<T>>{
using type = T;
};
template<typename C>
using extracted_type = typename extract_impl<std::remove_pointer_t<std::decay_t<C>>>::type;
template< class C >
void create_obj()
{
static_assert(std::is_same_v<extracted_type<C>,int>);
}
int main()
{
create_obj<R<int>>();
}
The convention is that R
would itself expose the type via using
, but you wrote that it is unchangeable.
Upvotes: 2