具有可选返回值的 lambda 参数

lambda parameter with optional return value

本文关键字:lambda 参数 返回值      更新时间:2023-10-16

我正在尝试编写一个像std::for_each这样的函数,除了正常用法外,还可以std::function<bool (param)>。错误的返回值意味着我想脱离循环。下面的代码是我到目前为止得到的。

a.visit([&](int) -> void) 的第二次调用在评估 !visitor(i) 时不编译。是否有可能完成这项工作,还是我吠错了树?

我使用的是 MSVC 2010,但希望代码通常与 C++11 兼容。

#include <list>
#include <string>
#include <iostream>
struct A 
{
    std::list<int> _lst;
    template<typename _F>
    void visit(_F visitor) 
    {
        for(std::list<int>::const_iterator it = _lst.begin(), end = _lst.end() ; it != end ; it++) {
            int i = *it;
            if (std::is_void<decltype(visitor(i))>::value) {
                visitor(i);
            } else {
               if (!visitor(i)) { // <----- error C2171: '!' : illegal on operands of type 'void'
                   break;
               }
            }
        }
    }
};
int main(int argc, char* argv[])
{
    A a;
    // populate a
    for (int i = 0 ; i < 10 ; i++) { 
        a._lst.push_back(i); 
    }
    a.visit([](int i) -> bool {
        std::cout << i << std::endl;
        return i < 5;
    });
    a.visit([](int i) {
        std::cout << i << std::endl;
    });
}

这是我实现for_almost_each的方式;出于可读性的目的,我using namespace std加上类型别名。

#include <algorithm>
#include <iterator>
#include <functional>
using namespace std;
template<class Iter, class Func>
Iter
for_almost_each_impl(Iter begin, Iter end, Func func, std::true_type)
{
    for (auto i = begin; i!=end; ++i)
        if (!func(*i))
            return i;
    return end;
}
template<class Iter, class Func>
Iter
for_almost_each_impl(Iter begin, Iter end, Func func, std::false_type)
{
    for_each(begin, end, func);
    return end;
}

template<class Iter, class Func>
Iter for_almost_each(Iter begin, Iter end, Func func)
{
    using Val = typename iterator_traits<Iter>::value_type;
    using Res = typename result_of<Func(Val)>::type;
    return for_almost_each_impl(begin, end,
                                func,
                                is_convertible<Res, bool>{} );
}

我用了is_convertible,因为它似乎比is_same更有意义。

你的 std::is_void 需要在编译时完成,不能在函数体内完成。这种函数重载的使用将起作用:

#include <list>
#include <string>
#include <iostream>
#include <type_traits> // missing header
struct A 
{
    std::list<int> _lst;
    // wrapper for bool returning visitor
    template<typename _F, typename Iter>
    bool do_visit(_F visitor, Iter it, std::true_type)
    {
      return visitor(*it);
    }
    // wrapper for non-bool returning visitor
    template<typename _F, typename Iter>
    bool do_visit(_F visitor, Iter it, std::false_type)
    {
      visitor(*it);
      return true;
    }
    template<typename _F>
    void visit(_F visitor) 
    {
        for (auto it = _lst.begin(), end = _lst.end() ; it != end ; it++) {
            // select correct visitor wrapper function using overloading
            if (!do_visit(visitor, it, std::is_same<bool, decltype(visitor(0))>())) {
              break;
            }
        }
    }
};
int main(int argc, char* argv[])
{
    A a;
    // populate a
    for (int i = 0 ; i < 10 ; i++) { 
        a._lst.push_back(i); 
    }
    a.visit([](int i) -> bool {
        std::cout << i << std::endl;
        return i < 5;
    });
    a.visit([](int i) {
        std::cout << i << std::endl;
    });
}

此 lambda 不返回值,这就是为什么您收到"visitor"返回 void 的错误:

a.visit([](int i) {
    std::cout << i << std::endl;
});

您可以通过重写为:

a.visit([](int i) -> bool {
    std::cout << i << std::endl;
    return true;
});