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

时间:2019-06-05 01:46:03

标签: c++ templates lambda language-lawyer function-pointers

我正在尝试使用带有模板作为参数的函数指针。但是编译器似乎在处理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;
}        

1 个答案:

答案 0 :(得分:6)

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

  

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

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

您可以在non-deduced context的帮助下,将第二个功能参数设为std::type_identity,以将其排除在推论之外。

  

type_identity可用于阻止template argument deduction

例如

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

LIVE

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