c ++函数多态性/模板

问题描述

我的目标是提供三种调用函数 listen()方法。有一个更好的方法吗? (比如使用模板或认值参数,所以我只能实现一个 listen() 函数
我目前的方法

void listen(const int &port,const std::function<void(std::string err)> &f) {
    http_server_.listen(port,[f](std::string err) { f(err); });
}
void listen(const int &port,const std::function<void()> &f) {
    http_server_.listen(port,[f](std::string err) { f(); });
}
void listen(const int &port) {
    http_server_.listen(port,[](std::string err) {});
}

我尝试了看起来像这样的模板方法

template <typename Func> void listen(const int &port,Func f = {}) {
    // do some if-else here.
}

但它不起作用。

解决方法

IMO,您的方法接近最佳。如果我在写这个,我只会做一些小的改动:

void listen(int port,std::function<void(const std::string &err)> f)
{
    http_server_.listen(port,std::move(f));
}
void listen(int port,std::function<void()> f)
{
    http_server_.listen(port,[f = std::move(f)](const std::string &){f();});
}
void listen(int port)
{
    // Are you sure the lambda is needed? Maybe passing `nullptr` will work.
    http_server_.listen(port,[](const std::string &){});
}

这里,lambda 捕获中的 f = std::move(f)(而不是 f)至少需要 C++14。如果您仅限于 C++11 并且不能这样做,那么您应该将 f 改回由 const 引用传递(在第二个重载中)。


在 C++17 之前无法轻松地将这些组合成单个函数,并且需要更多的样板文件,而不是将要消除的。

在 C++17 中你可以使用 if constexpr,但如果你问我,它仍然只会让事情变得更糟:

template <typename,typename...> struct always_false : std::false_type {};

template <typename F = std::nullptr_t>
void listen(int port,F &&f = nullptr)
{
    if constexpr (std::is_nullptr_v<std::remove_const_t<std::remove_reference_t<F>>>)
    {
        http_server_.listen(port,[](const std::string &) {});
    }
    else
    {
        http_server_.listen(port,[f = std::forward<F>(f)](const std::string &err)
        {
            if constexpr (std::is_invocable_v<const F &,const std::string &>)
                std::invoke(f,err);
            else if constexpr (std::is_invocable_v<const F &>)
                std::invoke(f);
            else
                static_assert(always_false<F>,"The function is invalid.");
        });
    }
}

这不仅需要两倍的输入,还可以防止调用者使用 SFINAE 检查您的函数接受或不接受哪些函数参数。

,
void listen(int port,std::function<void(std::string err)> f) {
  http_server_.listen(port,std::function<void()> f={}) {
  listen(port,[f=std::move(f)](std::string err) { f(); });
}

这更干燥。在 中,您可以节省一些开销:

void listen(int port,std::invocable<std::string> auto f) {
  http_server_.listen(port,std::invocable<> auto f=[]{}) {
  listen(port,[f=std::move(f)](std::string const&) { f(); });
}

使用概念,但我不会打扰。