0

我对函数有疑问,更具体的是函数签名以及如何传递它们。我可能是一个微不足道甚至愚蠢的问题,但我还找不到令人满意的答案。

请考虑这个使用 astd::unique_ptr来管理文件指针的示例:

#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;
}

这种智能指针需要一个函数签名作为第二个模板参数(shared_ptr不是出于某种奇怪的原因)。我目前对这里解释签名的理解是

void ( ) (FILE ) 是一个指向不返回任何内容的函数的指针 (void) 和一个文件指针作为参数。

结果,用户必须使用地址运算符传递所需函数的地址。此时,出现了几个问题:

1.) 删除地址运算符同样有效,不会引发编译器警告,代码有效。这不应该是一个错误/警告吗?

2.)如果我使用对函数的引用(例如unique_ptr<FILE, void(&)(FILE*)>(f, func1)),它会按预期工作,那么这是传递函数的一种更好的方式,因为它是明确的吗?

3.) 完全删除中间说明符(例如unique_ptr<FILE, void()(FILE*)>(f, func1))会导致编译器错误,那么按值传递函数通常是不可能的吗?(如果是,那么通过将函数隐式转换为函数指针来重载 1. 中的版本是有意义的)

4

1 回答 1

1

函数名是函数的总地址(指向函数的指针)。如果您想使用其他东西,您可以使用一些包装器,例如 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 是匿名功能对象。

于 2022-02-11T02:43:33.780 回答