Search code examples
c++templatesc++14template-specializationtype-deduction

Template specialization with non-empty template parameter list


I have difficulties to understand the following code

template <typename T>
struct function_traits
    : public function_traits<decltype(&T::operator())>
{};
// For generic types, directly use the result of the signature of its 'operator()'

template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
// we specialize for pointers to member function
{
  // ...
}

int main()
{
    auto lambda = [](int i) { return long(i*10); };

    typedef function_traits<decltype(lambda)> traits;

    // ...

    return 0;
}

which occurs in the answer https://stackoverflow.com/a/7943765/7006673.

Here,

template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>

seems to indicate a specialization of the template class

template <typename T>
struct function_traits

however, the template parameter list of the specialization template <typename ClassType, typename ReturnType, typename... Args> is not empty (i.e., is not equal to template <>). Can someone please help me to understand, what kind of specialization this is and how the template parameters ClassType, ReturnType, and Args are deduced?

Many thanks in advance.


Solution

  • What kind of specialization this is?

    This is a partial specialization. type_traits is explicitly instantiated with:

    T = ReturnType(ClassType::*)(Args...) const
    

    But this T is dependent on ReturnType, ClassType, and Args. That is why you don't have template <> in the declaration (that would be a full specialization), but a template declaration with new parameters describing a particular kind of T.

    How the template parameters ClassType, ReturnType, and Args are deduced?

    They are deduced when the template is instantiated with an expression that suits this specialization. Here, ReturnType(ClassType::*)(Args...) const can only be substituted with a pointer to a method.

    This is an example of SFINAE.