Search code examples
c++templatesoverload-resolution

Forbid automatic type inference


I have following demonstration code:

template <int i, typename T, typename U>
T func(const U &t){return i * t;}

template <int i, typename T>
T func(const T &t){return 2 * i * t;}

int main()
{
        return func<1, int>(1);
}

Which is a boiled down version of my real code, so it seems useless but should suffice to show the problem:

In function ‘int main()’:                                                  
11:23: error: call of overloaded ‘func(int)’ is ambiguous
11:23: note: candidates are:
2:3: note: T func(const U&) [with int i = 1, T = int, U = int]
5:3: note: T func(const T&) [with int i = 1, T = int]

So it is clear that the automatic type inference (for template parameter U) interferes with my interests of picking the right version of the template function (which is the one that has only 2 parametrs)

I need both versions to have a basic and a specialized template, that do things a little different.

So the question is: Is there any possibility to tell the compiler not to infer the type automatically at this point (for example by somehow saying: Take the template that has only 2 parameters)?


Solution

  • You can pass an initializer list, which effectively disables deduction (but causes list-initialization of parameters which in this case of int has the same effect though):

    template <int i, typename T, typename U>
    T func(const U &t){return i * t;}
    
    template <int i, typename T>
    T func(const T &t){return 2 * i * t;}
    
    int main()
    {
            return func<1, int>({1});
    }
    

    But in your case, if you call func<N>(...) you seem to want to call the second one, and if you call func<N, T>(...) you always seem to want to call the second one too, and only for func<N, T, U>(...) you want to call the first one, so you can always disable deduction for U by making the parameter a nondeduced context for it

    template <int i, typename T, typename U>
    T func(typename std::common_type<const U &t>::type t){return i * t;}
    
    template <int i, typename T>
    T func(const T &t){return 2 * i * t;}
    
    int main()
    {
            return func<1, int>({1});
    }