c++functionc++11signaturefunction-signature

Inconsistencies with C++11 function signatures


I have questions regarding functions, more specific on function signatures and how to pass them. I might be a trivial or even stupid question, but I couldn't find a satisfying answer yet.

Please consider this example which uses a std::unique_ptr to manage a file pointer:

#include <iostream>
#include <memory>

void func1(FILE* f)
{
    std::cout << "func1 called" << std::endl;
    fclose(f);
}

int main() 
{
    FILE* f = fopen("testfile.txt", "w");
    if(f)
    {
        std::unique_ptr<FILE, void(*)(FILE*)> fptr(f, &func1);
    }

    return 0;
}

This kind of smart pointer needs a functions signature as second template argument (shared_ptr does not for some odd reason). My current understanding of interpreting the signature here is

void () (FILE) is a pointer to a function returning nothing (void) and a filepointer as argument.

As a result, the user has to pass the address of the desired function with the address operator. At this point, a few questions arise:

1.) Removal of the address operator works just as well, no compiler warning is thrown, code works. Shouldn't this be an error/warning?

2.) If I use a reference to a function (e.g. unique_ptr<FILE, void(&)(FILE*)>(f, func1) ) it works as expected, so is this a superior way to pass a function as it is unambiguous?

3.) Removing the middle specifier altogether (e.g. unique_ptr<FILE, void()(FILE*)>(f, func1) ) causes compiler errors, so is passing a function by value impossible in general? (if it is, then it would make sense to overload the version in 1. by implicitly converting the function to a function pointer)


Solution

  • Function name is the always address of function (pointer to the function). If you want to use something else you can use some wrapper, e.g. std::function:

    #include <iostream>
    #include <memory>
    #include <functional>
    
    class Closer {
    public:
        void operator ()(FILE *f) {
            std::cout << "func1 called" << std::endl;
            fclose(f);
        }
    };
    
    int main() 
    {
        FILE* f = fopen("testfile.txt", "w");
        if(f)
        {
            std::unique_ptr<FILE, std::function<void(FILE*)>> fptr(f, Closer());
        }
    
        return 0;
    }
    

    Lambda in that case is anonymous functional object.