为什么我的函数重载不如我的模板化函数重载?

Why is my function overload not preferred over my templated one?

根据这个问题的第一个答案:function template overloading“非模板化(或“较少模板化”)重载优于模板”

#include <iostream>
#include <string>
#include <functional>

void f1(std::string const& str) {
    std::cout << "f1 " << str << "\n";
}

template <typename Callback, typename... InputArgs>
void call(Callback callback, InputArgs ...args) {
    callback(args...);
}

void call(std::function<void(std::string const&)> callback, const char *str) {
    std::cout << "custom call: ";
    callback(str);
}

int main() {
    auto f2 = [](std::string const& str) -> void {
        std::cout << "f2 " << str << "\n";
    };

    call(f1, "Hello World!");
    call(f2, "Salut Monde !");

    return 0;
}

据我所知,call 的第二个定义是“非模板化”的,因此当我做 call(f1, "1")call(f2, "2").

事实并非如此,我得到以下输出:

f1 Hello World!
f2 Salut Monde !

如果我删除 call 的模板化版本,我会得到预期的输出。

为什么在这种情况下没有选择我的 call 重载而不是第一个重载?

lambda f2 的类型不是 std::function<void(std::string const&)>,而是 is a compiler generated type。因此,模板化 call 提供了更好的匹配。

f1f2 都不是 std::function<...> 类型。因此模板是一个更好的匹配。

如果您使用(例如)

std::function<void(std::string const&)> f3(f2);
call(f3, "Salut Monde !");

您的电话已被使用。

std::function 可以由函数或 lambda 表达式构造,但其类型 与函数或 lambda 表达式不同。参数不完全匹配:

call(f1, "Hello World!");
call(f2, "Salut Monde !");

您可以使用转换来完成它:

call(static_cast<std::function<void(std::string const&)>>(f1), "Hello World!");
call(static_cast<std::function<void(std::string const&)>>(f2), "Salut Monde !");

LIVE

f1f2 的类型不是 std::function,需要用户定义的转换,因此选择模板版本。

如果您确实提供了一个与函数指针完全匹配的函数call,例如;

void call (void(*callback)(std::string const&), const char *str)

它将被选为 f1


注意:通过在lambda上添加一元+,在这种情况下你也可以获得一个函数指针(你的捕获列表是空的)。 ..

auto f2 = +[](std::string const& str) -> void
//        ^ unary +

当你用特定类型(函数的第二个参数)重载函数时,在这种情况下,当你用特定参数调用函数时,模板函数将不会调用,因为你已经为特定类型编写了函数。除了你的模板函数调用的特定类型,它是编译器作业select特定类型参数,然后是模板函数