簡體   English   中英

c ++ 14用於函數綁定的Variadic lambda捕獲

[英]c++14 Variadic lambda capture for function binding

我目前正在閱讀一些書籍以了解c ++ 14的功能。 我試圖使用可變參數模板將參數綁定到函數。 我知道如何使用std :: bind執行此操作,但我還想使用c ++ 14 lambda表達式實現此函數,僅用於常識和理解,以及任何可能的性能優勢。 我已經讀過lambdas可以內聯而std :: bind不能內聯,因為它是通過調用函數指針來實現的。

以下是myFunctions.h的代碼:

#include <functional>

int simpleAdd(int x, int y) {
    return x + y;
}

//function signatures
template<class Func, class... Args>
decltype(auto) funcBind(Func&& func, Args&&...args);

template<class Func, class... Args>
decltype(auto) funcLambda(Func&& func, Args&&...args);

/////////////////////////////////////////////////////////////////

//function definitions
template<class Func, class... Args>
inline decltype(auto) funcBind(Func&& func, Args&&... args)
{
    return bind(forward<Func>(func), forward<Args>(args)...);
}

template<class Func, class ...Args>
inline decltype(auto) funcLambda(Func && func, Args && ...args)
{   //The error is caused by the lambda below:
    return [func, args...]() {
        forward<Func>(func)(forward<Args>(args)...);
    };
}

這是我正在運行的主要代碼:

#include<iostream>
#include<functional>
#include "myFunctions.h"
using namespace std;


int main()
{
    cout << "Application start" << endl;
    cout << simpleAdd(5,7) << endl;

    auto f1 = funcBind(simpleAdd,3, 4);
    cout << f1() << endl;

    //error is occurring below
    auto f2 = funcLambda(simpleAdd, 10, -2);
    cout << f2() << endl;

    cout << "Application complete" << endl;

錯誤C2665'std :: forward':2個重載中沒有一個可以轉換所有參數類型

錯誤C2198'int(__ cdecl&)(int,int)':調用的參數太少

我認為當可變參數轉發到lambda時可能會發生錯誤,但我不太確定。

我的問題是如何正確地制定這個代碼,以便我可以使用lambda來捕獲函數及其參數,並在以后調用它。

我已經讀過lambdas可以內聯而std :: bind不能內聯,因為它是通過調用函數指針來實現的。

如果你將simpleAdd傳遞給然后綁定參數的東西,那么你是否使用bind並不重要。 你覺得lambda用func捕獲了什么? 這是一個函數指針。

lambda-vs-function-pointer案例是關於編寫bind(simpleAdd, 2, 3)[] { return simpleAdd(2, 3); } [] { return simpleAdd(2, 3); } 或綁定一個lambda像[](auto&&...args) -> decltype(auto) { return simpleAdd(decltype(args)(args)...); } [](auto&&...args) -> decltype(auto) { return simpleAdd(decltype(args)(args)...); }與結合simpleAdd直接(將使用函數指針)。


無論如何,實施它是非常棘手的。 你不能使用by-reference capture,因為事情很容易晃來晃去,你不能使用簡單的按值捕獲,因為即使對於rvalues也會復制參數,你不能在init中進行包擴展-捕獲。

這遵循std::bind的語義(調用函數對象並將所有綁定參數作為lvalues傳遞),除了1)它不處理占位符或嵌套綁定,以及2)函數調用運算符總是const

template<class Func, class ...Args>
inline decltype(auto) funcLambda(Func && func, Args && ...args)
{   
    return [func = std::forward<Func>(func), 
            args = std::make_tuple(std::forward<Args>(args)...)] {
        return std::experimental::apply(func, args);
    };
}

cppreference有一個std::experimental::apply

請注意,這會解開reference_wrapper ,就像bind一樣,因為make_tuple

您的原始代碼打破了,因為argsconst在lambda的函數調用操作(這是const默認設置),以及forward結束試圖拋棄常量性。

你使用一個元組:

template<class Func, class ...Args>
inline decltype(auto) funcLambda(Func && func, Args && ...args)
{   //The error is caused by the lambda below:
    auto tpl = make_tuple(std::forward<Args>(args)...);

    //Use move just in case Args has move-only types.
    return [func, tpl = move(tpl)]() {
        apply(func, tpl);
    };
}

apply定義如下

namespace detail {
template <class F, class Tuple, std::size_t... I>
constexpr decltype(auto) apply_impl( F&& f, Tuple&& t, std::index_sequence<I...> )
{
  return f(std::get<I>(std::forward<Tuple>(t))...);
}
} // namespace detail

template <class F, class Tuple>
constexpr decltype(auto) apply(F&& f, Tuple&& t)
{
    return detail::apply_impl(std::forward<F>(f), std::forward<Tuple>(t),
        std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>>::value);
}

apply是庫TS版本之一的一個特性。 使用C ++ 17, apply_impl可以調用invoke ,這適用於任何可調用的

暫無
暫無

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

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