直接将lambdas传递到函数

Passing lambdas directly to functions

本文关键字:函数 lambdas      更新时间:2023-10-16

我正在编写一个Option类,该类代表可能存在或不存在的值。if_opt函数旨在采用Option和一个函数,该函数将在Option中持有的值中调用,但仅在值存在时。

template <class T>
class Option {
private:
    std::shared_ptr<T> m_value;
public:
    explicit operator bool()const noexcept
    {
        return (bool)m_value;
    }
    Option() = default;
    explicit Option(T value)
    {
        m_value =  std::make_shared<T>(value);
    }
    template <class U>
    friend void if_opt(Option<U>&, std::function<void(U&)>);
};
template <class T>
void if_opt(Option<T>& opt, std::function<void(T&)> f)
{
    if (opt) f(*opt.m_value);
};

我注意到如果我这样使用的话,这有效:

Option<int> none;
Option<int> some(10);
function<void(int&)> f1 = [](int& none)
{
    cout << "This should never be reached" << endl;
};
function<void(int&)> f2 = [](int& some)
{
    cout << "The value of some is: " << some << endl;
};
if_opt(none, f1);
if_opt(some, f2);

但是我想能够将lambda表达直接放在通话中,但是当我这样做时:

if_opt(none, [](int&)
{
    cout << "This should never be reached" << endl;
});
if_opt(some, [](int& some)
{
    cout << "The value of some is: " << some << endl;
});

我有一个错误:

error: no matching function for call to 'if_opt(Option<int>&, main()::<lambda(int&)>)'

我知道标准中的lambda表达式的类型是不确定的,并且仅必须分配给 std::function<R(T)>,所以这种有意义,但是有一种方法可以使我可以使lambda参数隐含转换为std::function<void(T&)>,以便我可以以我尝试的方式定义 if_opt的lambda?

std::function<Sig>是一种类型的擦除工具。它(几乎(擦除了有关它存储的excpet的所有内容,它可以用Sig调用。

模板参数扣除进行类型的传递并推论应使用的类型,然后生成模板函数,并(通常(调用。

这些几乎彼此之间。在类型的擦除模板上进行扣除是代码气味,几乎总是一个坏主意。

这是您的基本设计错误。


有多种修复代码的方法。

首先, if_opt不应该是模板。

friend void if_opt(Option<T>& opt, std::function<void(T&)> f){
  if (opt) f(*opt.m_value);
}

这创建了我所说的Koenig朋友。您必须定义身体内联。确实,该U类型毫无意义,甚至在某些情况下可能会导致错误。

但是,这里的类型擦除也毫无意义。修复返回模板的修复,但现在是有充分理由的。

template<class F>
friend void if_opt(Option<T>& opt, F&& f){
  if (opt) f(*opt.m_value);
}

这是一个更好的设计。

您可以去投资Sfinae超载分辨率代码,但我不会打扰。

template<class F,
  std::conditional_t<true, bool,std::result_of_t<F&(T&)>> = true
>
friend void if_opt(Option<T>& opt, F&& f){
  if (opt) f(*opt.m_value);
}

上面是晦涩的,并且比上方的边际优势最小。