带有模板的 C++ 函数指针参数

C++ function pointer argument with template

我正在尝试使用带有模板的函数指针作为参数。但是编译器似乎无法处理 lambda 和 nullptr。

当我在下面的代码中将 void (*callback)(T input) 更改为 void (*callback)(int input) 时一切正常。

此编译器行为是否由 C++ 标准指定?

我使用的编译命令是 $ g++ main.cpp -std=c+11,但在 Visual Studio 2019 中发现了相同的行为。

template <class T>
int dummy (T tmp, void (*callback)(T input)) {
    // Doesn't do anything, just trying to compile
    // If I change (T input) to (int input), it compiles fine  
    if (callback)
        return 1;
    else
        return 0;
}

void callback (int input) {
    return;
}

int main () {
    int tmp = 10;
    auto callback_lambda = [](int input) -> void {
        return;
    };

    dummy(tmp, callback); // Compiles OK
    dummy(tmp, callback_lambda); // Error: mismatched types 'void (*)(T)' and 'main()::<lambda(<int>)'
    dummy(tmp, nullptr); // Error: no matching function for call to 'dummy(int&, std:nullptr_t)'
    return 0;
}        

问题是在template argument deduction中不会考虑隐式转换。

Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.

所以在传递lambda和nullptr时,没有考虑到函数指针的转换,模板参数T不能推导出第二个函数参数,然后导致错误.

您可以将第二个函数参数设为non-deduced context, to exclude it from deduction, with the help of std::type_identity

type_identity can be used to block template argument deduction:

例如

template <class T>
int dummy (T tmp, void (*callback)(std::type_identity_t<T>)) {
    ...
}

LIVE

PS:如果你的编译器不支持std::type_identity (C++20 起),你可以定义你自己的版本,这并不困难。