Search code examples
c++templatesc++17function-pointers

Can an address of an instant of a template to a function be passed as a pointer to function to some function?


I have the following code which compiles without any problem

#include<iostream>
#include<vector>

template<typename T>
void compare(const std::vector<T> &v1, const std::vector<T> &v2, void(*func)(const int&,const int&,const size_t&))
{
    size_t minLen{v1.size() < v2.size() ? v1.size() : v2.size()};

    for(size_t index{}; index<minLen; index++)
        func(v1[index],v2[index],index);

}

template<typename T>
void matcher(const T& val1,const T& val2,const size_t& index)
{
    if(val1==val2) std::cout<<"v1 and v2 are equal at index "<<index<<"\n";

}


int main()
{
    std::vector v1={1,5,-9,-8};
    std::vector v2={1,5,-9,-80,45};
    compare(v1,v2,&(matcher<int>));
    return 0;
}

Now I have the following question : Is compare(v1,v2,&(matcher<int>)); equivalent to compare(v1,v2,&matcher); and why

An Edit

When I delete the const before index var in matcher, the compiler shows the following error

temp.cpp(85): error C2664: 'void compare1<int>(const std::vector<int,std::allocator<int>> &,const std::vector<int,std::allocator<int>> &,void (__cdecl *)(const int &,const int &,const size_t &))': cannot convert argument 3 from 'void (__cdecl *)(const T &,const T &,size_t &)' to 'void (__cdecl *)(const int &,const int &,const size_t &)'
temp.cpp(85): note: None of the functions with this name in scope match the target type
temp.cpp(64): note: see declaration of 'compare1'

The compiler says

'void (__cdecl *)(const T &,const T &,size_t &)' to 'void (__cdecl *)(const int &,const int &,const size_t &)'

It doesn't say

'void (__cdecl *)(const int &,const int &,size_t &)' to 'void (__cdecl *)(const int &,const int &,const size_t &)'

Solution

  • compare(v1,v2,&matcher); works because of template argument deduction.

    Template argument deduction is used when taking an address of a overload set, which includes function templates.

    and

    If the function name names a function template, then, first, template argument deduction is done, and if it succeeds, it produces a single template specialization which is added to the set of overloads to consider.

    The 3rd function parameter type of compare is void(*func)(const int&,const int&,const size_t&), when pass &matcher, the template parameter T of matcher is deduced as int, the effect is just same as specifying the template argument explicitly as matcher<int>.

    BTW: What kind of message get printed out depends on the implementation of compiler; e.g. clang gives different one.