超载&&对于lambdas

时间:2016-12-14 11:45:06

标签: c++ lambda types

我希望为lambdas重载运算符&&,该lambdas将任意(单个)值作为输入,并产生bool,例如:

auto operator&&( func_t lhs, func_t rhs )
{
  return []( auto x ){ return lhs(x) && rhs(x) };
}

但是,我不知道如何定义func_t以便它对应于所需lambda的类型(即,一个lambda采用任意单个输入并产生bool

有谁知道如何实施?

2 个答案:

答案 0 :(得分:4)

我不确定这是一个好主意,因为正如molbdnilo提到的那样,你不会发生短路,在我看来代码将是误导读者。

无论如何,std::function是一种代价高昂的抽象,应该避免使用,因为你不需要它的功能。

使用模板功能std::enable_if将起作用:

template <typename T>
using returns_bool_when_called_with_int = 
    std::is_same<decltype(std::declval<T&>()(std::declval<int>())), bool>;

template <typename T0, typename T1>
using lambda_and_enabler = std::enable_if_t
<
    returns_bool_when_called_with_int<T0>{} && 
    returns_bool_when_called_with_int<T1>{}
>;

template <typename T0, typename T1, typename = lambda_and_enabler<T0, T1>>
auto operator&&( T0 lhs, T1 rhs ) 
{
    // Note that `lhs` and `rhs` are being captured by copy.
    // See the note at the end of the post for a more general alternative.
    return [=]( auto x ){ return lhs(x) && rhs(x); };
}

上面的代码可以按如下方式使用:

int main()
{
    auto l0 = [](int x){ return x % 3 == 0; };
    auto l1 = [](int x){ return x % 2 == 0; };
    auto l_and = l0 && l1;

    assert(l_and(6));

    assert(!l_and(5));
    assert(!l_and(4));    
}

wandbox example

注意:您可能希望将lhsrhs lambdas perfect forward放入operator&&返回的lambda中,以避免不必要的复制并支持引用语义。我最近写了一篇关于它的文章:"capturing perfectly-forwarded objects in lambdas"

您的通用operator&&函数将如下所示:

template <typename T0, typename T1,
    typename = lambda_and_enabler<std::decay_t<T0>, std::decay_t<T1>>>
auto operator&&(T0&& lhs, T1&& rhs) 
{
    return [lhs = FWD_CAPTURE(lhs), rhs = FWD_CAPTURE(rhs)](auto&& x) mutable
    { 
        return access(lhs)(x) && access(rhs)(x); 
    };
}

答案 1 :(得分:0)

如果已知lambda的参数,则可以使用强制转换为std::function,如下所示:

std::function<bool (int)> operator &&( std::function<bool (int)> lhs, std::function<bool (int)> rhs )
{
  return [&]( int x ){ return lhs(x) && rhs(x); };
}

用法:

auto f = [](int x){ return false; } && [](int x){ return true; };