4

I have a template class inside another template class. How can I write a template function that will accept any combination of inner/outer template class?

template <class X>
struct A
{
  template <class Y>
  struct B
  {
    int q;
  };
};

template <class X, class Y>
int f( typename A<X>::template B<Y>& ab )
{
  return ab.q;
}

int g( A<char>::B<short>& ab )
{
  return f( ab ); // Error: Could not deduce template argument
}
Barnett
  • 1,491
  • 12
  • 18

2 Answers2

2

This template accepts any combination of inner and outer:

tempalte <typename T>
int f(T& ab)
{
    return ab.q;
}    

You cannot deduce X and Y from typename A<X>::template B<Y>. See here for details: What is a nondeduced context?. The fundamental issue is that there is no 1:1 relation between the actual type that the name typename A<X>::template B<Y> refers to and X and Y. Consider that there could be a specialization:

template <>
struct A<double>
{
    template <class Y>
    using B = A<int>::B<Y>;
};

Now A<double>::B<Y> and A<int>::B<Y> refer to the same type. Given one or the other there is no way to unambiguously deduce X.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
2

The compiler is not allowed to infer the template arguments in this context, so in order to transport the type information, you have to make it explicit. One possibility is to provide aliases:

template <class X>
struct A
{
  template <class Y>
  struct B
  {
    using X_type = X;
    using Y_type = Y;
    int q;
  };
};

template <class T>
int f( T& ab )
{
  return ab.q;
}

int g( A<char>::B<short>& ab )
{
  return f( ab );
}

This way, you still have access to the types as e.g. typename T::X_type.

Jodocus
  • 7,493
  • 1
  • 29
  • 45
  • My problem is that I already have a `template int f( T& )` for the general case. I need another overload of `f()` for when `T` is an `A::B`. I am going to have to try something with `std::enable_if`... – Barnett May 21 '21 at 10:41
  • @Barnett maybe open another question with more context. – 463035818_is_not_an_ai May 21 '21 at 10:46
  • @largest_prime_is_463035818, if for example I already have a function `template int f( T& t ) { return sizeof(t); }`, but now I need another overload of `f()` that will return `A::B::q`. – Barnett May 21 '21 at 11:01
  • @Barnett yes I think I understood the issue, and I think I know a solution, though its not the issue this question is about, and comments are not the place to talk about lengthy code (anything just a bit longer than what you wrote is not readable / understandable in comments). – 463035818_is_not_an_ai May 21 '21 at 11:04
  • @largest_prime_is_463035818, don't worry, I got it working with `template int f( T& )`, as suggested by @Jodocus. – Barnett May 21 '21 at 11:49