为什么我的函数重载不优先于我的模板化重载

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

本文关键字:重载 我的 函数 为什么 优先于      更新时间:2023-10-16

根据这个问题的第一个答案:函数模板重载,"非模板化(或"模板化较少")重载比模板更可取"。

#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没有选择第一个?

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

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

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

它将被选为f1.


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

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

lambda f2的类型不是std::function<void(std::string const&)>,它是一个编译器生成的类型。因此,模板化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 !");

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