c++c++14method-reference

C++ equivalent of Java's method references?


I have a std::vector<std::vector<int>>, from which I want to check whether there is at least 1 sub-vector that's empty. So I have this:

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

Is there something like this in C++14?

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

I tried the above syntax, which didn't work. Nor did sticking a & in front of the method work, as one source claimed.


Solution

  • Using the lambda is the readable way.

    Only for illustration lets explore other ways. The predicate p needs to be (from cppreference):

    The expression p(v) must be convertible to bool for every argument v of type (possibly const) VT, where VT is the value type of InputIt, regardless of value category, and must not modify v. Thus, a parameter type of VT& is not allowed, nor is VT unless for VT a move is equivalent to a copy(since C++11). ​

    Implicit conversions aside, this basically means, the predicate must be a callable with signature bool (const std::vector<int>&).

    std::function is a candiate. It comes with considerable overhead, because its main purpose is type erasure. We do not need type erasure, but std::function also has a mechanism to turn a member function pointer into a callable where the object is passed to the function. Ie we can transform &std::vector<int>::empty, a member function pointer, into something with signature bool (const std::vector<int>&). So far so good, but this transformation isnt implicit and does not play well with class template argument deduction. As a consequence the syntax is rather clumsy:

    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));
    }
    

    Live Demo

    Um... We can turn the member function pointer into a callable with right signature, but std::function isnt really what is needed here and it does not help for terse syntax. How about writing a custom wrapper:

    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>{});
    }
    

    This leads to nice syntax on the call. Passing the member function directly is not possible, but this is as close as it can get. However, class_type is a bit of a cheat here. You'd need more specializations to cover all const / non-const, not noexcept etc variants. And it gets much worse when the member function is overloaded. Its not something you actually want to write.

    Live Demo

    Conclusion: A lambda expression is the lightweight, easy to read way to wrap the member function. I doubt it can get any more readable.