【问题标题】:C++ function pointer argument with template带有模板的 C++ 函数指针参数
【发布时间】:2019-10-20 12:58:29
【问题描述】:

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

【问题讨论】:

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


    【解决方案1】:

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

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

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

    您可以将第二个函数参数设置为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起),你可以定义自己的版本,不难。

    【讨论】:

    • 这很好解释。看着std::type_identity,我的印象是C++ 变得越来越复杂。不管怎样,谢谢你的回答!
    • 我发现std::type_identity_t&lt;void(*)(T)&gt; callbackvoid (*callback)(std::type_identity_t&lt;T&gt;) 更具可读性
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-20
    • 1970-01-01
    • 2014-04-14
    • 1970-01-01
    • 1970-01-01
    • 2018-01-03
    • 2017-02-24
    相关资源
    最近更新 更多