Search code examples
c++templatestemplate-argument-deduction

Why can't T be deduced from Class<T>::MemberClass?


In the following mcve:

template <typename T> class Class { public: class MemberClass {}; };

#include <list>

template <typename T>
Class<T> func(const typename Class<T>::MemberClass& start, 
              const typename Class<T>::MemberClass& finish)
{
    Class<T> result; return result;
}

int main ()
{
    Class<int>::MemberClass i, j;
    Class<int> L2; L2 = func(i, j);

    return 0;
}

I find that the compiler does not recognize the function as something that can take the given arguments. In Visual Studio the error is

1>C:\...\main.cpp(15,25): error C2672: 'func': no matching overloaded function found
1>C:\...\main.cpp(15,34): error C2783: 'Class<T> func(const Class<T>::MemberClass &,const Class<T>::MemberClass &)': could not deduce template argument for 'T'
1>C:\...\main.cpp(6): message : see declaration of 'func'

In g++, here are the errors:

main.cpp:15:34: error: no matching function for call to 'func(Class<int>::MemberClass&, Class<int>::MemberClass&)'
   15 |     Class<int> L2; L2 = func(i, j);
      |                                  ^
main.cpp:6:10: note: candidate: 'template<class T> Class<T> func(const typename Class<T>::MemberClass&, const typename Class<T>::MemberClass&)'
    6 | Class<T> func(const typename Class<T>::MemberClass& start,
      |          ^~~~
main.cpp:6:10: note:   template argument deduction/substitution failed:
main.cpp:15:34: note:   couldn't deduce template parameter 'T'
   15 |     Class<int> L2; L2 = func(i, j);
      |                                  ^                                     ^

I'm sure there's another way to write the function (it could return a MemberClass not a Class), but, well, this should be doable. How can I make that happen?


Solution

  • Quite literally, every possible T that matches your Class has a MemberClass type. The compiler is not going to look inside all of them to find a match, because it'd have to instantiate templates just to see their contents, and it would potentially match too many things. So the langauge simply doesn't look inside like that.

    The way you can solve this is to tell the compiler what T is when you call it, here, providing an explicit int template argument:

    func<int>(i, j);