Template Function Overload Resolution: A Quick Reference

Reading time ~6 minutes


Motivation and Use Cases

SFMT and dSFMT provides utilities to fill an array with random numbers using SIMD. This provides an excellent opportunity to build faster Random number generators than those offered by the STL. The only problem is that the vectorized RNGs offered are only for certain types. The problem is visualized in the figure above. Let’s say we have a general purpose templated matrix class and we want our Matrix<T>::random() to automatically select the the most efficient implementation based on type T. So our aim is to come up with a way to overload either member-function or free-function templates in the best way.


Explicit/Full Specialization

  1. Code Snippet: (Try Online!)
    template <typename T>
    struct Foo{
     void method();
    };
    //
    template <typename T>
    void Foo<T>::method() {
     std::cout << "default method " << std::endl;
    }
    // 
    template <>
    void Foo<int32_t>::method() {
     std::cout << "int32 method " << std::endl;
    }
    //
    template <>
    void Foo<int64_t>::method() {
     std::cout << "int64 method " << std::endl;
    }
    
  2. Pros: Extremely simple to implement.
  3. Cons: Requires manual repetition if needing to implement the same functionality across different types. For eg. with the problem introduced in the motivation above fill_array(SFMT) would have to be rewritten twice for uint32_t/uint64_t.

Tag Dispatch

  1. Code Snippet:(Online link in next bullet)
    template <typename T>
    struct Foo{
     void unary_td(std::true_type) {
         std::cout << "integral type!" << std::endl;
     }
     void unary_td(std::false_type) {
         std::cout << "non-integral type!" << std::endl;
     }
        
     void unary_td() {
         unary_td(std::is_integral<T>{});
     }
    };
    
  2. Variations/Examples:
  3. Pros: For simple overload resolution conditions tag dispatch is easily the most readable and simple while avoiding repetition. In short, the perfect first choice.
  4. Cons: For complex conditions(as can be seen as we go from Unary to Nary tag dispatch) the complexity of tag dispatch greatly increases. Additionally, based on the template type, conditional disabling of other functions or overloads is not possible. More on this in the references.

SFINAE: Substitution Failure is not an error

When calling a templated function, the compiler will form a set of candidate overloads and try each one in turn from best to worst matching. As suggested in this title, any failure to match any specific overload signature to the function call is not treated as an error. If matches on all overload candidates fail, its an error.

  1. Code Snippet:(Online link in next bullet)
    template <typename U>
    auto sfinae() -> std::enable_if_t<!std::is_same<U, int>::value && !std::is_same<U, float>::value> {
     std::cout << "sfinae default" << std::endl;
    }
    //
    template <typename U>
    auto sfinae() -> std::enable_if_t<std::is_same<U, int>::value> {
     std::cout << "sfinae int" << std::endl;
    }
    // 
    template <typename U>
    auto sfinae() -> std::enable_if_t<std::is_same<U, float>::value> {
     std::cout << "sfinae float" << std::endl;
    }
    
  2. Variations/Examples:
  3. Pros: Allows conditionally disabling overloads, Potentially simpler when needing overloading resolution on complex conditions.
  4. Cons: Clearly, it can be tricky to implement.

References and Further Reading

This post was more of a quick summary on the different techniques involved in template function overload resolution. For more detailed reading you can refer to the following:

  1. Foonathan Series on Overload Resolution: Covers all the methods here and more in a lot of detail.
  2. Usefulness of SFINAE over others: As discussed earlier this is covered in this and this.
  3. Macros for Overload Resolution uses Macros for explicit specialization of matrix equality for floating point types while typing substantially lesser.
    Also, the final solution for the problem I mentioned above was by using SFINAE coded up here.

That’s all, thanks for reading :) - You can post a comment or reach out to me at saatvikshah1994@gmail.com.

Paper Summary: Kafka

A short visual summary of the original Kafka paper. Continue reading