Bum*_*Kim 9 c++ lambda templates function-pointers language-lawyer
我正在尝试使用带有模板的函数指针作为参数。但是编译器似乎在处理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;
}        
问题在于模板参数推导中将不考虑隐式转换。
类型推导不考虑隐式转换(上面列出的类型调整除外):这是超载解析的工作,稍后会发生。
因此,当传递lambda和时nullptr,不考虑对函数指针的转换,T无法为第二个函数参数推断出模板参数,从而导致错误。
您可以在的帮助下将第二个函数参数设为非推导上下文,以将其从推论中排除std::type_identity。
type_identity可以用来阻止模板参数推导:
例如
template <class T>
int dummy (T tmp, void (*callback)(std::type_identity_t<T>)) {
    ...
}
PS:如果您的编译器不支持std::type_identity(自C ++ 20起),则可以定义自己的版本,这并不困难。