可变参数函数指针转换

8

我正在编写一个库,其中包含许多函数对象,这些函数对象的类有几个operator()重载,这些重载不依赖于类的状态,也不会对其进行修改。现在,我尝试让我的代码与许多旧式API一起工作(这不是一个随意的需求,我实际上必须处理这样的API),因此决定将函数对象转换为与其中一个重载相对应的任何函数指针。在某个时刻,我意识到我有太多的这种转换函数指针运算符,理论上我应该能够编写一个单一的可变参数转换运算符。以下是实现这种可变参数运算符的类:

struct foobar
{
    template<typename... Args>
    using fptr_t = void(*)(Args... args);

    template<typename... Args>
    operator fptr_t<Args...>() const
    {
        return [](Args... args) {
            // Whatever
        };
    }
};

正如您所看到的,我使用了lambda转换为函数指针来实现转换操作符,这并不是一个问题,因为我拥有的每个函数对象都是无状态的。目标是能够按照以下方式使用该类:

int main()
{
    void(*foo)(int) = foobar();
    void(*bar)(float, double) = foobar();
}

使用g++编译此代码没有问题,符合预期的语义。然而,clang++ 拒绝 并显示模板替换失败错误:

main.cpp:21:11: error: no viable conversion from 'foobar' to 'void (*)(int)'
    void(*foo)(int) = foobar();
          ^           ~~~~~~~~
main.cpp:11:5: note: candidate function [with Args = int]
    operator fptr_t<Args...>() const
    ^
1 error generated.
请注意,只要没有涉及可变模板参数,clang++对此类转换运算符没有问题。如果我使用单个模板参数,它将能够成功编译代码。那么,上面的代码应该被编译器接受还是拒绝?

4
我认为这是与此问题相同的bug。也有一个相关的SO问题。Richard Smith 表示这是一个bug,所以我相信他 :)。 - Jesse Good
解决方法:使用 template<class F> operator F*() 进行转换,添加 sfinae 测试以确保它是函数类型,使用 traits 提取参数,使用 helper 解包,使用 helper 转换为指针。 - Yakk - Adam Nevraumont
1个回答

2
如果lambda表达式没有捕获任何变量,那么它只能转换为函数指针,所以您的代码应该可以工作。这在标准文献5.1.2/p6 Lambda expressions [expr.prim.lambda]中有正当理由:闭包类型是一个不带泛型的lambda表达式,并且没有lambda捕获,它具有公共的非虚拟、非显式的const转换函数,可以将其转换为具有C++语言链接(7.5)的函数指针,参数和返回类型与闭包类型的函数调用运算符相同。此转换函数返回的值应为一个函数地址,当调用它时,具有与调用闭包类型的函数调用运算符相同的效果。
因此,我会将其归档为CLANG bug。
如果要解决CLANG问题,可以将其转换为std::function,如下所示:
struct foobar
{
    template<typename... Args>
    using fptr_t = void(*)(Args... args);

    template<typename... Args>
    operator std::function<void(Args...)>() const
    {
        return [](Args... args) {
            //...
        };
    }
};

int main()
{
    std::function<void(int)> f1 = foobar();
    std::function<void(double, float)> f2 = foobar();
    f1(1);
    f2(2.0, 1.0f);
}

Live Demo


嗯,是的,我知道所有这些。我的意思是,我不是在寻求解决方案(我已经解决了一段时间了)。我只是想要一个语言专家的答案,以便知道应该向哪个编译器提交错误报告:p - Morwenn
@Morwenn 你需要向 CLANG 提交一个错误报告 :P。 - 101010

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接