将无参数泛型 lambda 转换为函数指针

Mar*_*zek 3 c++ lambda

我正在尝试将无参数通用 lambda 转换为函数指针。此问题通常适用于泛型 lambda,其参数不依赖于模板实参。

示例尝试使用一个参数 () 来转换 lambda int,该参数在类型上与模板参数无关T

#include <iostream>

int main()
{
    auto lambda = []<class T>(int v) -> void
    {
        std::cout << typeid(T).name() << ' ' << static_cast<T>(v) << '\n';
    };

    // How do I cast lambda to a function pointer that uses operator(int)<char>
    // This doesn't compile, I've reached this conclusion after examining this page https://en.cppreference.com/w/cpp/language/lambda
    auto seeked_ptr_char = lambda.operator fptr_t<char>();

    // Hacky solution :(
    auto mptr_char = &decltype(lambda)::operator()<char>;
    decltype(mptr_char) mptr_float = &decltype(lambda)::operator()<float>;

    (lambda.*mptr_char)(48);
    (lambda.*mptr_float)(52);

    // This is okay (tho parameter is dependent on a template argument, which is not what we are looking for)
    auto another_lambda = []<class T>(T v) -> void
    {
        std::cout << v << '\n';
    };

    void(*ptr_char)(char) = another_lambda;
    ptr_char(50);
 
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

不编译 x86-64 gcc 12.1 with -std=c++20 -O3

x86-64 clang 14.0.0 -std=c++20 -O3

https://godbolt.org/z/cavbT5jM3

Nic*_*las 6

如何将 lambda 转换为使用的函数指针operator(int)<char>

TL;DR:你不知道。

首先,函数指针指向函数。模板还不是函数;只有当您向函数模板提供模板参数时,函数模板才会成为函数。函数指针可以指向函数模板的特定实例。但它不能指向函数模板。

从通用 lambda 到函数指针的转换依赖于调用模板转换函数。因此,lambda 实际上具有如下转换函数:

using func = void(int);

template<typename T>
operator func*();
Run Code Online (Sandbox Code Playgroud)

然而,这是一个模板转换函数。由于要转换的类型不提供模板参数,因此为了调用该函数,您必须显式提供该类型。这意味着您必须显式调用转换函数。

但考虑到您编写的代码,您已经解决了所有问题。这意味着你真正的问题是:

如果转换结果与模板参数没有任何关系,如何显式调用模板转换函数?

Lambda 在这里并不重要。这都是关于调用一种特殊的模板转换函数。

答案是……显然,你不知道

type_name您可以通过语法显式调用类型转换函数object_name.operator type_name()。问题是标准中的这一行

conversion-function-id 中的 conversion-type-id 是可能形成 conversion-type-id 的最长标记序列。

问题是如何lambda.operator fptr_t<char>()解析。看,fptr_t 可能是模板类的名称。因此,fptr_t<char> 可能是该类模板的专门化的名称。因此是“可能形成转换类型 IDfptr_t<char>的最长令牌序列”。

简而言之,编译器认为您正在尝试调用类型的转换函数fptr_t<char>。不是模板并不重要,编译器可以环顾四周并找出答案fptr_t解析发生在任何此类思考之前。所以解析规则优先。整个fptr_t<char>文本被视为转换函数的类型名。

这一切都意味着,除非可以从要转换的类型单独推导出转换函数的模板参数,否则似乎不可能调用这样的转换函数。这样的转换函数是可以存在的;你可以声明这样的函数就可以了。但 C++ 缺乏任何与其实际交互的语法。

具有无法从函数参数推导的模板参数的 lambda 并不是特别有用的另一个原因。