C++20 'familiar template' lambdas: specifying an explicit argument in function pointer conversion

Viewed 142

Assuming I have the following code in C++20, using the explicit template argument lambda functionality introduced in P0428:

auto f = []<auto val>(int a) { printf("%d", val + a); };

and I need a function pointer conversion for the lambda f to void(*)(int) with an explicitly specialized value (I need an explicit C ABI linkage there, member function calls will lead to different argument passing registers), given the fact that the following code is illegal:

using intfn = void(*)(int);
f.template operator intfn<400>(); // illegal
f.template operator()<400>(0); // legal, but not what I need: is a member function call

(seeing the answer to Is it possible to call templated user-defined conversion operator with explicit template arguments?)

... is there any other way to get a function pointer in the current C++ language, e.g. by using some sort of implicit conversion?

1 Answers

You can leverage the fact that a non-capturing lambda is default-constructible in c++20.

#include <iostream>
#include <tuple>

template <typename F>
struct args_tuple_maker;

template <auto P, typename F, typename... Args>
auto make_function_pointer(F, std::tuple<Args...>) {
    return +[](Args... args){ F{}.template operator()<P>(std::forward<Args>(args)...); };
}

int main() {
    auto f = []<auto val>(int a) { printf("%d", val + a); };

    auto f_ptr = make_function_pointer<200>(f, std::tuple<int>{});

    static_assert(std::is_same_v<decltype(f_ptr), void(*)(int)>, "");

    f_ptr(5);
}

It's not a perfect solution, but maybe as close as you can get right now. Could probably be improved to deduce the arguments from the lambda type.

Related