为什么我的函数超载不是我的模板优先?

时间:2016-03-08 09:06:05

标签: c++ templates c++11 overload-resolution

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

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

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

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 << std::endl;
    };

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

    return 0;
}

根据我的理解,call的第二个定义是“非模板化”,因此当我call(f1, "1")或{{1}时,应该选择第一个定义。 }。

情况并非如此,我得到以下输出:

call(f2, "2")

如果删除f1 Hello World! f2 Salut Monde ! 的模板版本,我会得到预期的输出。

为什么call的超载在这种情况下没有超过第一个?

5 个答案:

答案 0 :(得分:6)

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

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

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

将为f1选择它。

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

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

答案 1 :(得分:3)

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

答案 2 :(得分:3)

f1f2都不属于std::function<...>类型。因此模板更匹配。

如果您使用(例如)

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

您的通话已被使用。

答案 3 :(得分:1)

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

答案 4 :(得分:-1)

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