Template argument deduction with template class inside template class

Viewed 57

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
}
2 Answers

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.

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.

Related