簡體   English   中英

C++:將 lambda 指針作為函數指針傳遞

[英]C++: Passing lambda pointer as a function pointer

我想在 C++ 中獲取隱式函數的值。 為簡單起見,假設我對函數 x(a) 感興趣,它由 x*x - a == 0 定義。

我有一個使用布倫特方法的根查找器,它被聲明為

BrentsFindRoot( double (*f)(double), double a, double b, double tol )

由於第一個參數是一個指向函數 double -> double 的指針,我想我可以通過使用 lambda 函數來實現這一點。 所以我定義了

auto Foo(double a) {
    auto f = [a] (double x) noexcept -> double {
        return x*x - a;
    };
    return f;
}

我想我可以通過調用BrentsFindRoot(&Foo(2),0,10,1e-10)來獲得sqrt(2) BrentsFindRoot(&Foo(2),0,10,1e-10) 但是,編譯器抱怨它不能將 lambda 函數轉換為函數指針。 我看,這是可以做到只有當lambda函數沒有捕獲任何,但對我來說,它需要捕捉a

那么這里的解決方案是什么? 有沒有辦法將Foo(2)傳遞給BrentsFindRoot 或者,我如何重新聲明BrentsFindRoot以便它接受 lambda 函數?

我正在使用 C++17

您的BrentsFindRoot采用無狀態函數指針。

你的 lambda 有狀態。

這些不兼容。 無論是概念上還是語法上。

BrentsFindRoot( double (*f)(void const*, double), void const*, double a, double b, double tol )

如果您添加狀態並希望它保持純 C 函數,這就是簽名的變化方式。 然后傳遞 lambda 在概念上是有效的,但語法很笨拙。 如果您不介意根查找器中的 C++:

BrentsFindRoot( std::function<double(double)> f, double a, double b, double tol )

或者,您可以通過表/全局狀態技巧將狀態硬塞為無狀態函數指針。 您還可以通過獲取和存儲與a等效a作為編譯時參數來使 lambda 無狀態。

但只需執行std::function版本。

如果BrentsFindRoot是僅標題功能,則可以使用模板

template<class F>
void BrentsFindRoot( F f, double, double, double );

最后一個選擇是查找或編寫function_view類型; 通過避免存儲,這可以比std::function更有效。

union function_state {
  void* pvoid;
  void(* pfvoid)();
  function_state(void* p=nullptr):pvoid(p) {}
  template<class R, class...Args>
  function_state(R(*pf)(Args...)):pfvoid(reinterpret_cast<void(*)()>(pf)) {}
};
template<class Sig>
struct function_view;
template<class R, class...Args>
struct function_view<R(Args...)> {
  function_state state;
  R(*pf)(function_state, Args&&...args) = nullptr;

  R operator()(Args...args)const {
    return pf(state, std::forward<Args>(args)...);
  }
  function_view(function_view const&)=default;
  function_view& operator=(function_view const&)=default;
  explicit operator bool() const{ return pf; }

  function_view( R(*f)(Args...) ):
    state(f),
    pf([](function_state s, Args&&...args)->R{
      return reinterpret_cast<R(*)(Args...)>(s.pfvoid)( std::forward<Args>(args)... );
    })
  {}


  template<class F, std::convertible_to<R> FR=std::invoke_result_t< F, Args... >>
  requires (!std::is_same_v<R,void>)
  function_view( F&& f ):
    state((void*)std::addressof(f)),
    pf([](function_state s, Args&&...args)->R{
      return (*static_cast<F*>(s.pvoid))( std::forward<Args>(args)... );
    })
  {}
  template<class F>
  requires (std::is_same_v<R, void>)
  function_view( F&& f ):
    state((void*)std::addressof(f)),
    pf([](function_state s, Args&&...args)->void{
      (*static_cast<F*>(s.pvoid))( std::forward<Args>(args)... );
    })
  {}


  template<std::convertible_to<R> R0, std::constructible_from<Args>...As>
  requires (!std::is_same_v<R,void>)
  function_view( R0(*f)(As...) ):
    state(f),
    pf([](function_state s, Args&&...args)->R{
      return reinterpret_cast<R0(*)(As...)>(s.pfvoid)( std::forward<Args>(args)... );
    })
  {}
  template<class R0, std::constructible_from<Args>...As>
  requires (std::is_same_v<R, void>)
  function_view( R0(*f)(As...) ):
    state(f),
    pf([](function_state s, Args&&...args)->void{
      reinterpret_cast<R0(*)(As...)>(s.pfvoid)( std::forward<Args>(args)... );
    })
  {}
};

但這可能不是你想要寫的東西。

除了函數指針或std::function ,您也可以使用模板:

template<class Callback>
void BrentsFindRoot(Callback const& f, double a, double b, double tol ) {
    // ...
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM