Reputation: 562
Consider the following piece of C++ code:
int main(){
MyObject<int> obj;
foo(obj);
}
template <typename T>
void foo(T& objct){
...
}
In foo, the type of objct
will be MyObject<int>
.
I would like to create a variable in foo()
whose type is the objct
's generics, in this case, int
.
Is there a way to do that? Thank you.
Edit
Unfortunately (I think) I can't rewrite the signature because the function foo()
is called with different type of objects, for example
int main(){
MyObject<int> obj;
MyDifferentObject<int> obj2;
foo(obj);
foo(obj2);
}
Upvotes: 0
Views: 271
Reputation: 238401
I would like to create a variable in foo() whose type is the objct's generics, in this case, int. Is there a way to do that?
If you can change the function signature, then you can do this:
template <typename T>
void foo(MyObject<T>& objct){
T variable;
If that is not an option, for example if you want foo
to allow other templates too (such as in your edited question), then you can define a type trait:
template<class T>
struct fancy_type_trait
{
};
template<class T>
struct fancy_type_trait<MyObject<T>>
{
using type = T;
};
template<class T>
struct fancy_type_trait<MyDifferentObject<T>>
{
using type = T;
};
template <typename T>
void foo(T& objct){
using V = typename fancy_type_trait<T>::type;
V variable;
Upvotes: 3
Reputation: 66230
What about defining foo()
using a template-template parameter?
template <template <typename...> class C, typename T>
void foo (C<T> & objct)
{
/...
}
or also
template <template <typename...> class C, typename T, typename ... Ts>
void foo (C<T, Ts...> & objct)
{
/...
}
to be more flexible and accept also type with multiple template types parameters.
This way, if you call
MyObject<int> obj;
MyDifferentObject obj2;
foo(obj);
foo(obj2);
you have that C
is MyObject
in first case, MyDifferentObject
in the second case and T
is int
in both cases.
This, obviously, works only if the argument of foo()
are object of a template class with only template type parameters so, for example, doesn't works for std::array
std::vector<int> v;
std::array<int, 5u> a;
foo(v); // compile: only types parameters for std::vector
foo(a); // compilation error: a non-type template parameter for std::array
Upvotes: 3
Reputation: 122724
You can write a trait that determines the first template parameter of any instantiation of a template with one template parameter:
#include <type_traits>
template <typename T>
struct MyObject {};
template <typename T>
struct MyOtherObject {};
template <typename T>
struct first_template_parameter;
template <template<typename> typename T,typename X>
struct first_template_parameter< T<X> > {
using type = X;
};
int main() {
static_assert(std::is_same< first_template_parameter<MyObject<int>>::type,
first_template_parameter<MyOtherObject<int>>::type>::value );
}
The trait first_template_parameter
can take any instantiation of a template with a single parameter and tells you what that parameter is. first_template_parameter< MyObject<int> >::type
is int
. More generally first_template_parameter< SomeTemplate<T> >::type
is T
(given that SomeTemplate
has one parameter).
This is a slight generalization of the trait used in this answer and if needed it could be generalized to also work for instantiations of tempaltes with more than one parameter.
In your function you would use it like this:
template <typename T>
void foo(T& objct){
typename first_template_parameter<T>::type x;
}
Upvotes: 2