模板函数指针和 lambda

template function pointers and lambdas

您好,我正在尝试使用以下代码解决问题:

template<typename... Args>
using Func = void (*)(Args... args);

template<typename... Args>
void do_test(Func<Args&...> f, Args&... args) {
    for (int i = 0; i != 100; i++)
      f(args...);
}

int main(){
    int x = 0;
    do_test(Func<int&>([](int &y) { y++; }), x);  // OK

    // Error - mismatched types 'void (*)(Args& ...)' and 'main()::<lambda(int&)>'
    do_test([](int &y) { y++; }, x);

    return x;
}

https://godbolt.org/z/UaXxFJ

任何人都可以解释为什么需要将 lambda 包装在 Func<int&>( ) 中吗?有办法避免吗? - 因为如果参数列表很重要,那么必须两次列出参数类型会变得非常乏味。

这里的目标是创建一个编译器可以优化的访问者模式。我将它用于图像处理算法,我想在其中重用外部循环的代码,以及各种内部代码。 Args 被用作类似于 lambda 捕获的东西,除了使用传统的函数指针以便编译器可以优化它们 - 这似乎无法使用 std::function<>

您可以只允许函数采用任何类型,无论是函数指针还是 lambda:

template<typename F, typename... Args>
void do_test(F f, Args&... args) {
    for (int i = 0; i != 100; i++)
      f(args...);
}

根据您的用例,考虑采用 f by-const-reference 或 forwarding reference(即 F&&),作为嗯。

您还应该考虑更改获取 args 函数参数的方式。通常在这种情况下,您会通过 转发引用 获取它们,意思是 Args&&... args 而不是 Args&... args。否则您将无法使用右值参数调用该函数。


或者如果您有某些特定原因只接受这个特定的函数指针类型,您可以将第一个函数参数设为非推导上下文,前提是模板参数已经可以从其他函数参数推导出来:

template<typename... Args>
void do_test(std::type_identity_t<Func<Args&...>> f, Args&... args) {
    for (int i = 0; i != 100; i++)
      f(args...);
}

std::type_identity_t 是 C++20 的特性,但很容易实现:

template<typename T>
struct type_identity {
    using type = T;
};

template<typename T>
using type_identity_t = typename type_identity<T>::type;

type_identity<T>::type 中范围解析运算符 :: 的所有内容都是非推导上下文,因此第一个函数参数不会用于推导 Args,其中turn 表示将考虑隐式转换(例如 lambda 到函数指针的转换)。

或者,正如@FrançoisAndrieux 在问题评论中提到的,您可以使用 lambda + 技巧在调用站点将 lambda 转换为函数指针:

do_test(+[](int &y) { y++; }, x);

另请注意,采用此特定类型的函数指针意味着只能使用 完全 这种类型的函数调用该函数。例如 args 总是推导为引用类型,因此任何可能与此函数一起使用的函数都必须仅采用引用参数。这通常不是您想要的。通常你想要 std::function<R(Args...)> 的松散行为,它可以从任何 可调用 的函数对象构造,具有指定的 Args 和 returns 东西可以隐式转换为 R.