Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ function pointer argument with template

I'm trying to use a function pointer with template as an argument. But the compiler seems to have trouble handling lambda and nullptr.

Everything is fine when I change void (*callback)(T input) to void (*callback)(int input) in the following code.

Is this compiler behavior specified by the C++ standard?

The compile command I use is $ g++ main.cpp -std=c+11 but the same behavior found in 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;
}        
like image 282
Bumsik Kim Avatar asked Jun 05 '19 01:06

Bumsik Kim


1 Answers

The problem is that implicit conversion won't be considered in 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.

So when passing lambda and nullptr, the conversions to the function pointer aren't considered, the template parameter T can't be deduced for the 2nd function argument and then cause the error.

You can make the 2nd function parameter to 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:

e.g.

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

LIVE

PS: If your compiler doesn't support std::type_identity (since C++20), you can define your own version, it's not difficult.

like image 115
songyuanyao Avatar answered Sep 19 '22 16:09

songyuanyao