簡體   English   中英

有沒有辦法將`constexpr`值傳遞給lambda,以便在lambda中保持`constexpr`?

[英]Is there a way to pass a `constexpr` value into lambda so that it remains `constexpr` inside that lambda?

這就是我想要做的; 發布整個代碼,因為它不會太長,也是為了演示我正在嘗試解決的具體任務。 基本上,我需要一種方法來從參數包中按索引迭代值(索引部分很重要,即使在此示例中不需要)。

#include <iostream>
#include <tuple>
#include <type_traits>

template <int First, int Last, typename Functor>
constexpr void static_for(Functor&& f)
{
    if constexpr (First < Last)
    {
        f(std::integral_constant<int, First>{});
        static_for<First + 1, Last, Functor>(std::forward<Functor>(f));
    }
}

template <size_t index, typename... Args>
auto value_by_index(Args&&... args) noexcept {
    return std::get<index>(std::forward_as_tuple(std::forward<Args>(args)...));
}

template <typename... ValueTypes>
void traverse(ValueTypes... values)
{
    static_for<0, sizeof...(ValueTypes)>([&](int i) {
        auto v = value_by_index<static_cast<size_t>(i), ValueTypes...>(values...);
        std::cout << v << std::endl;
    });
}

int main()
{
    traverse(0.0f, 1, 3.33, "str");

    return 0;
}

編譯器錯誤當然是:

<source>:24:71: error: 'i' is not a constant expression

如果lambdas可以有明確的模板參數,那么i就是這樣一個參數,對於編譯器而言,它在編譯時是已知的。 但這不是lambdas的工作方式。

如果你想把它當作一個XY問題,我想我並不需要在static_for調用一個lambda,但我確實需要調用一些可以通過索引訪問traverse參數包的代碼,如果traverse是一個成員函數,我需要訪問它的this

在線試用: https//godbolt.org/z/eW4rnm

使用通用lambda和constexpr轉換運算符

template <typename... ValueTypes>
void traverse(ValueTypes... values)
{
    static_for<0, sizeof...(ValueTypes)>([&](auto I)
    //                                       ~~~^
    {
        auto v = value_by_index<I>(values...);
        //                     ~^~
        std::cout << v << std::endl;
    });
}

DEMO

使用lambda表達式的模板參數列表:

template <typename... ValueTypes>
void traverse(ValueTypes... values)
{
    static_for<0, sizeof...(ValueTypes)>([&]<int I>(std::integral_constant<int, I>)
    //                                       ~~~~^                             ~^~
    {
        auto v = value_by_index<I>(values...);
        //                     ~^~
        std::cout << v << std::endl;
    });
}

演示2

玩太晚了?

基本上,我需要一種方法來從參數包中按索引迭代值(索引部分很重要,即使在此示例中不需要)。

抱歉,但是... std::make_index_sequencestd::index_sequence舊用法std::make_index_sequence std::index_sequence

維護你的value_by_index() ,我提出了基於traverse()traverse_helper()的以下C ++ 14解決方案

template <typename F, std::size_t ... Is, typename ... VTs>
void traverse_helper (F f, std::index_sequence<Is...>, VTs ... vs)
 { 
   using unused = int[];

   (void)unused { 0, (f(value_by_index<Is>(vs...)), 0)... };
 }

template <typename F, typename ... VTs>
void traverse (F f, VTs ... vs)
 { traverse_helper(f, std::make_index_sequence<sizeof...(VTs)>{}, vs...); }

注意我也傳遞了callable作為參數。

如果你可以使用C ++ 17(如你標記的話), traverse_helper()就變成了

template <typename F, std::size_t ... Is, typename ... VTs>
void traverse_helper (F f, std::index_sequence<Is...>, VTs ... vs)
 { (f(value_by_index<Is>(vs...)), ...); }

您可以按如下方式調用traverse()

traverse([](auto x){ std::cout << x << std::endl; },
         0.0f, 1, 3.33, "str");

以下是完整的C ++ 14編譯示例

#include <iostream>
#include <tuple>
#include <type_traits>

template <std::size_t I, typename ... As>
auto value_by_index (As && ... as) noexcept
 { return std::get<I>(std::forward_as_tuple(std::forward<As>(as)...)); }

template <typename F, std::size_t ... Is, typename ... VTs>
void traverse_helper (F f, std::index_sequence<Is...>, VTs ... vs)
 { 
   using unused = int[];

   (void)unused { 0, (f(value_by_index<Is>(vs...)), 0)... };
 }

template <typename F, typename ... VTs>
void traverse (F f, VTs ... vs)
 { traverse_helper(f, std::make_index_sequence<sizeof...(VTs)>{}, vs...); }

int main ()
 {
    traverse([](auto x){ std::cout << x << std::endl; },
             0.0f, 1, 3.33, "str");
 }

暫無
暫無

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

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