c++templates

Why can void(*deleter)(int) be a template parameter?


I have the following class:

#include <iostream>

template <typename T, void(*deleter)(T)>
struct MyMoveOnlyHandleType
{

    void reset() { deleter(handle); }
    T handle;
    ~MyMoveOnlyHandleType() { reset(); }
};

int main() {
    {
        MyMoveOnlyHandleType<int, [](int arg) {
            std::cout << "Hello";
            } > my_handle;
    }
}

And it compiles on all three major compilers after c++17. However, I don't understand how void(*deleter)(T) can be given as a template parameter, because ordinarily this is a function pointer.

I'm assuming that it's interpreted as a "non-type template parameter". OK. Ordinarily a "type template parameter" looks like this:

template <typename T>

And a non-type template parameter looks like this:

template <int N>

So, I assumed that the right way to do this would be to first write the type, and then write the 'identifier':

template <void (*)(int) deleter>

The void (*)(int) would be declaring the type, and then the deleter would be the equivalent to N in template <int N>.

That compiles in Clang and GCC, but not in MSVC. Is that right?


Solution

  • So, I assumed that the right way to do this would be to first write the type, and then write the 'identifier':

    Declaring a function pointer does not follow the simple pattern of type name. You declare a function pointer to function with void return,int parameter, named foo, initialized to point to a function called bar like this:

    void (*foo)(int) = &bar;
    

    For more readability you can use a type alias:

    using func_type = void(*)(int);
    func_type foo = &bar;
    

    I'm assuming that it's interpreted as a "non-type template parameter". OK

    Right.