C++ 相当于 Java 的方法引用?

问题描述 投票:0回答:2

我有一个

std::vector<std::vector<int>>
,我想从中检查是否至少有 1 个子向量为空。所以我有这个:

std::any_of(vec.begin(), vec.end(), [](const auto& subvec)  {
     return subvec.empty();
});

C++14中有类似的东西吗?

std::any_of(vec.begin(), vec.end(), std::vector<int>::empty);

我尝试了上面的语法,但不起作用。正如一位消息人士声称的那样,在该方法前面添加

&
也不起作用。

c++ c++14 method-reference
2个回答
0
投票

使用 lambda 是一种可读的方式。

仅供参考,让我们探索其他方法。谓词

p
需要是(来自 cppreference):

对于类型(可能是 const)

p(v)
的每个参数
bool
,表达式
v
必须可转换为
VT
,其中
VT
InputIt
的值类型,无论值类别如何,并且不得修改
v
。因此,参数类型
VT&
是不允许的,
VT
也不允许,除非对于
VT
移动相当于复制(C++11 起)。

除了隐式转换之外,这基本上意味着,谓词必须是带有签名

bool (const std::vector<int>&)
的可调用函数。

std::function
是候选人。它带来了相当大的开销,因为它的主要目的是类型擦除。我们不需要类型擦除,但是
std::function
还有一种机制可以将成员函数指针转换为可调用对象,其中对象被传递给函数。也就是说,我们可以将成员函数指针
&std::vector<int>::empty
转换为具有签名
bool (const std::vector<int>&)
的东西。到目前为止一切顺利,但这种转换不是隐式的,并且不能很好地与类模板参数推导配合使用。因此,语法相当笨拙:

int main () {
    std::vector<std::vector<int>> vec;
    std::any_of(vec.begin(),vec.end(),std::function<bool(const std::vector<int>&)>(&std::vector<int>::empty));
}

现场演示

嗯...我们可以将成员函数指针转换为具有正确签名的可调用函数,但是

std::function
并不是这里真正需要的,并且它对简洁的语法没有帮助。编写自定义包装器怎么样:

template <typename T> struct class_type;
template <typename C> struct class_type<bool(C::*)() const noexcept> { using type = C;};

template <auto F>
struct bool_member_to_functor {    
    using type = typename class_type<std::decay_t<decltype(F)>>::type;
    bool operator()(const type& c) {
        return (c.*F)();
    }
};

int main (int argc, char** argv)
{
    std::vector<std::vector<int>> vec;
    std::any_of(vec.begin(),vec.end(),bool_member_to_functor<&std::vector<int>::empty>{});
}

这会导致调用时有良好的语法。直接传递成员函数是不可能的,但这已经是最接近的了。然而,

class_type
在这里有点作弊。您需要更多的专业化来涵盖所有
const
/非常量,而不是
noexcept
等变体。当成员函数重载时,情况会变得更糟。这不是你真正想写的东西。

现场演示

结论:lambda 表达式是包装成员函数的轻量级、易于阅读的方式。我怀疑它能否变得更具可读性。


0
投票

在评论中你说:

除了确实有一种更短且(可以说)更易读的方式来编写它之外,没有什么明显的错误,

所以看来你真正想要的是使用命名函数(一个很好的编程实践)。我们可以做到这一点并且仍然使用 lambda。只需创建一个命名的 lambda 即可。

#include <algorithm>

auto isEmpty = [](std::vector<int> const& v)  {return v.empty(); /* or std::empty(v) */};

int main()
{
    std::vector<std::vector<int>>   vec;

    auto f = std::any_of(std::begin(vec), std::end(vec), isEmpty);
}
© www.soinside.com 2019 - 2024. All rights reserved.