AlessandroF
AlessandroF

Reputation: 562

How to declare a variable whose type is the generics of another object?

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

Answers (3)

eerorika
eerorika

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

max66
max66

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

463035818_is_not_an_ai
463035818_is_not_an_ai

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

Related Questions