c++templates

When is it required to add the types for template code and when not?


I stumbled upon the fact that in C++ for the code

template<std::signed_integral T>
struct Ratio
{
    T Nominator; T Denominator;
    Ratio& operator+=(const Ratio& R);
    ...
};
template<std::signed_integral T>
Ratio<T>& Ratio<T>::operator+=(const Ratio& R)
{
  ...
}

the template parameter seems to be required to be repeated for the struct name in the return type and before the ::, but not for the parameter. Is there a clearcut rule for this? Why does the compiler assume, that the parameters are as defined in the introducing "template" line but it cannot or does not want to for the return type or the class name?


Solution

  • Classes (which includes structs) have something called injected-class-name in them, which acts as a (somewhat magical) typedef pointing to the class itself:

    template<std::signed_integral T>
    struct Ratio
    {
        using Ratio = Ratio<T>; // Pretend it works like this.
        // ...
    };
    

    This is what lets you omit template arguments. It only works inside of the scope of this class.

    In Ratio<T>& Ratio<T>::operator+=(const Ratio& R), we only know that we're inside of the class after we see Ratio<T>::, so that's when the injected-class-name becomes visible, and when the template arguments become optional.

    The trailing return type can help with this: auto Ratio<T>::operator+=(const Ratio& R) -> Ratio.