簡體   English   中英

如何在lambda中捕獲變量

[英]How to capture variable inside lambda

我有來自這里的代碼:

std::sort(begin(v), end(v), [](auto const &t1, auto const &t2) {
        return get<0>(t1) < get<0>(t2); // or use a custom compare function
});

我想多次對元組進行排序,所以我寫了這段代碼:

int k = 10;
while(k--){
    std::sort(begin(v), end(v), [](auto const &t1, auto const &t2) {
    return get<k>(t1) < get<k>(t2); // or use a custom compare function
    });
}

但我收到錯誤error: 'k' is not captured 我試圖這樣做:

int k = 10;
while(k--){
    std::sort(begin(v), end(v), [&k](auto const &t1, auto const &t2) {
    return get<k>(t1) < get<k>(t2); // or use a custom compare function
    });
}

但它不是正確的方法和錯誤error: the value of 'k' is not usable in a constant expression

如何捕獲k變量?

正如 mch 在評論中所說,問題在於k不是編譯時常量。

對於編譯時常量,要從N迭代到0 ,您可能需要模板和遞歸:

#include <algorithm>
#include <tuple>
#include <type_traits>
#include <vector>

using namespace std; // just for simplify, and not recommended in practice

template <size_t N, typename Iterator, enable_if_t<N == 0, int> = 0>
void foo(Iterator begin, Iterator end)
{
    sort(begin, end,
        [](const auto &t1, const auto &t2) {
            return get<0>(t1) < get<0>(t2); 
        }
    );
}

template <size_t N, typename Iterator, enable_if_t<N != 0, int> = 0>
void foo(Iterator begin, Iterator end)
{
    sort(begin, end,
        [](const auto &t1, const auto &t2) {
            return get<N>(t1) < get<N>(t2); 
        }
    );
    foo<N - 1>(begin, end);
}

int main()
{
    vector<tuple<int, int>> v{{0, 1}, {0, 0}, {1, 1}};
    foo<1>(v.begin(), v.end());

    // posible results:
    // {0, 0}, {0, 1}, {1, 1}
    // {0, 1}, {0, 0}, {1, 1} // impossible if use std::stable_sort instead
}

std::get只接受一個模板參數,它是一個表達式,其值可以在編譯時計算 你不能使用k ,因為它是一個改變值的變量。

std::sort(begin(v), end(v), [](auto const &t1, auto const &t2) {
    const int k = 3;
    return std::get<k>(t1) < std::get<k>(t2); // or use a custom compare function
});

正如我在評論中所寫的那樣,我知道const int = 3會隱藏 lambda 表達式之外的k值,但是這個示例表明get在收到編譯時間常量值時會起作用。 例如,如果您嘗試設置k = 5 ,例如其中v只有 4 個元組參數,編譯器將給出錯誤,因為它知道這超出了范圍。

下面的代碼會報錯,但是如果k設置為3就可以了

std::vector<std::tuple<int, int, int, int>> v;
std::sort(begin(v), end(v), [](auto const &t1, auto const &t2) {
            const int k = 5;
            return std::get<k>(t1) < std::get<k>(t2); // or use a custom compare function
        });
#include <tuple>
#include <utility>
#include <cstddef>
#include <algorithm>
#include <cstddef>
#include <iterator>

template <std::size_t I, typename It, typename F>
void sort_tuple(It it, It end, F f)
{
    std::stable_sort(it, end, [f](const auto& t1, const auto& t2)
    {
        return f(std::get<I>(t1), std::get<I>(t2));
    });
}

template <typename It, typename F, std::size_t... Is>
void sort_tuple(It it, It end, F f, std::index_sequence<Is...>)
{
    int dummy[] = { 0, (sort_tuple<sizeof...(Is) - Is - 1>(it, end, f), 0)... };
    static_cast<void>(dummy);
}

template <typename It, typename F>
void sort_tuple(It it, It end, F f)
{
    sort_tuple(it, end, f, std::make_index_sequence<
            std::tuple_size<typename std::iterator_traits<It>::value_type>::value
                           >{});
}

測試:

std::vector<std::tuple<int, int, int>> v{ {2,1,2}, {2,2,2}, {3,2,1}
                                        , {1,1,1}, {1,2,1}, {2,2,1} };

sort_tuple(begin(v), end(v), [](const auto& t1, const auto& t2)
{
    return t1 < t2;
});

for (auto& t : v)
{
    std::cout << std::get<0>(t) << " " << std::get<1>(t) << " " << std::get<2>(t) << std::endl;
}

演示

您使用k作為模板參數,因此它必須在編譯時可用。 通過使其成為constexpr來做到這一點的一種方法:

constexpr int k = 1;
int j = k;

while(j--){
    std::sort(begin(v), end(v), [&k](auto const &t1, auto const &t2) {
    return get<k>(t1) < get<k>(t2); // or use a custom compare function
    })
}

模板非類型參數必須是編譯時常量。 int k=0; 不是編譯時常量。

template<std::size_t...Is>
auto index_over(std::index_sequence<Is...> ={}){
  return [](auto&&f)->decltype(auto){
    return f( std::integal_constant<std::size_t,Is>{}... );
  };
}
template<std::size_t N>
auto index_upto(std::integral_constant<N> ={}){
  return index_over(std::make_index_sequence<N>{});
}

這些是從 0 到N-1獲得有效編譯時間值的助手。

auto foreacher=[](auto&&f){
  return [f](auto&&...args){
    using discard=int[];
    (void)discard{0,(void(
      f(decltype(args)(args))
    ),0)...};
  };
};

上面是晦澀的替換短的代碼。 foreacher(f)返回一個函數g g(a,b,c)執行f(a)然后f(b)然后f(c)

現在把它粘在一起:

auto sort_v_by_k=[&](auto k){
  std::sort(begin(v), end(v), [](auto const &t1, auto const &t2) {
    return get<k>(t1) < get<k>(t2); // or use a custom compare function
  });
};
index_upto<11>()( foreacher( [&](auto k){
  sort_v_by_k( std::integral_constant<std::size_t, 11-k >{} );
}));

並忽略錯別字,完成。

暫無
暫無

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

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