【问题标题】:Why is my function overload not preferred over my templated one?为什么我的函数重载不是我的模板化函数重载的首选?
【发布时间】:2023-04-06 13:13:02
【问题描述】:

根据这个问题的第一个答案: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 重载没有选择第一个?

【问题讨论】:

  • 只有当参数类型完全匹配时才首选非模板。在您链接到的线程中,请注意10 匹配非模板但10u 匹配模板的示例。

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


【解决方案1】:

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

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

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

它将被选为f1


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

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

【讨论】:

【解决方案2】:

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

【讨论】:

    【解决方案3】:

    f1f2 都不是 std::function&lt;...&gt; 类型。因此模板是更好的匹配。

    如果你使用(例如)

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

    您的电话已被使用。

    【讨论】:

      【解决方案4】:

      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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-11-16
          • 1970-01-01
          • 2017-05-04
          • 1970-01-01
          相关资源
          最近更新 更多