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

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;
}        
Run Code Online (Sandbox Code Playgroud)

son*_*yao 6

问题在于模板参数推导中将不考虑隐式转换。

类型推导不考虑隐式转换(上面列出的类型调整除外):这是超载解析的工作,稍后会发生。

因此,当传递lambda和时nullptr,不考虑对函数指针的转换,T无法为第二个函数参数推断出模板参数,从而导致错误。

您可以在的帮助下将第二个函数参数设为非推导上下文,以将其从推论中排除std::type_identity

type_identity可以用来阻止模板参数推导

例如

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

生活

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