简体   繁体   English

c++17 std::apply/invoke 什么时候需要编程?

[英]When is c++17 std::apply/invoke necessary for programming?

As long as c++ is object-oriented programming language, I'm not sure if std::apply or std::invoke are necessary utility, which converts:只要 c++ 是面向对象的编程语言,我不确定std::applystd::invoke是否是必要的实用程序,它转换:

Object.Function(Args...)

into:进入:

std::invoke(Object, Function, Args)

that looks like c-style function call.看起来像 c 风格的 function 电话。 So my question is, when is this kind of scenario a necessary/convenience for daily programming?所以我的问题是,这种场景什么时候是日常编程的必要/便利? Or else, is there a case that using apply / invoke makes things simpler?或者,是否存在使用apply / invoke使事情变得更简单的情况?

Would you help to give a good example case?你能帮忙举一个很好的例子吗? Thanks a lot!多谢!

std::invoke enables all Callable objects to be invoked uniformly , which contains pointers to member functions and pointers to member variables that cannot be invoked with regular function call form like f(args...) std::invoke允许统一调用所有Callable对象,其中包含指向成员函数的指针和指向无法使用常规 function 调用形式如f(args...)调用的成员变量的指针

struct S {
  void f(int i);
  int x;
};

int main() {
  auto mem_vptr = &S::x;
  auto mem_fptr = &S::f;
  S s;
  std::invoke(mem_vptr, s);    // invoke like s.*mem_vptr;
  std::invoke(mem_fptr, s, 0); // invoke like (s.*mem_fptr)(0);
}

One of the real use of std::apply is tuple unpacking, potentially nested. std::apply的真正用途之一是元组拆包,可能是嵌套的。 Here's tested example:这是经过测试的示例:


#include <iostream>

#include <string>
#include <tuple>
#include <sstream>

// adapted from here: https://stackoverflow.com/a/48458312
template <typename> 
constexpr bool is_tuple_v = false;

template <typename ...T> 
constexpr bool is_tuple_v<std::tuple<T...>> = true;

template<typename Tval, typename ... T>
void linearize_tuple(std::stringstream &outbuf, const Tval& arg, const T& ... rest) noexcept {
    if constexpr (is_tuple_v<Tval>){
        outbuf << "{ ";
        std::apply([&outbuf](auto const&... packed_values) {
                linearize_tuple(outbuf, packed_values ...);
            }, arg
        );
        outbuf << " }";
    }
    else{
        outbuf << arg;
    }

    if constexpr(sizeof...(rest) > 0){
        outbuf << ' ';
        linearize_tuple(outbuf, rest ...);
    }
}

template<typename ... T>
std::string args_to_string(const T& ... args) noexcept {
    std::stringstream outbuf{};
    if constexpr(sizeof...(args) > 0){
        linearize_tuple(outbuf, args ...);
    }
    return outbuf.str();
}

int main(){
    std::cout << args_to_string(
        "test", 1, "2", 3.0, '0', std::tuple
        {
            "examination", 10, "20", 30.0, '1', std::tuple
            {
                "we need to go deeper", 100, "200", 300, '2'
            }
        }
    );
}

It will print:它将打印:

test 1 2 3 0 { examination 10 20 30 1 { we need to go deeper 100 200 300 2 } }

and if you look at implementation of std::apply , it's probably using std::invoke like in example from cppreference .如果您查看std::apply的实现,它可能正在使用std::invoke ,就像cppreference 中的示例一样。 Key part:关键部分:

namespace detail {
template <class F, class Tuple, std::size_t... I>
constexpr decltype(auto) apply_impl(F&& f, Tuple&& t, std::index_sequence<I...>)
{
    // This implementation is valid since C++20 (via P1065R2)
    // In C++17, a constexpr counterpart of std::invoke is actually needed here
    return std::invoke(std::forward<F>(f), std::get<I>(std::forward<Tuple>(t))...);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM