AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 78713559
Accepted
Gene
Gene
Asked: 2024-07-06 08:03:45 +0800 CST2024-07-06 08:03:45 +0800 CST 2024-07-06 08:03:45 +0800 CST

convertendo tupla em problemas variantes

  • 772

Preciso acessar um valor std::tuplepor índice em tempo de execução. Para isso escrevi uma função que retorna a std::variantcom os mesmos tipos inicializados para o índice especificado. A implementação envolve instanciações de modelos recursivos:

template<std::size_t N>
constexpr auto get_n = [](/*tuple-like*/auto&& t, std::size_t index)
{
    using variant_type = decltype(std::apply([](auto&&... v){
        return std::variant<std::monostate, std::remove_cvref_t<decltype(v)>...>{};
    }, t));

    constexpr auto size = std::tuple_size_v<std::remove_cvref_t<decltype(t)>>;

    if constexpr(N > size)
        return variant_type{};
    else 
    {
        if(N == index + 1)
            return variant_type(std::in_place_index<N>, std::get<N - 1>(t));
        else
            return get_n<N + 1>(t, index);
    }
};

constexpr auto tuple_to_variant(/*tuple-like*/auto&& t, std::size_t index)
{
    return get_n<1>(std::forward<decltype(t)>(t), index);
}

Estou usando compiladores c++23. O problema é que apenas o gcc compila sem erros. Os compiladores clang e MSVC entram em loop infinito de instanciação. Isso é um bug nos compiladores? Como posso corrigir esse código que ele compila nos três compiladores?

Aqui está a demonstração do Compiler Explorer

c++
  • 4 4 respostas
  • 118 Views

4 respostas

  • Voted
  1. 康桓瑋
    2024-07-06T11:54:05+08:002024-07-06T11:54:05+08:00

    Como você está chamando o lambda recursivamente, isso só é possível com um parâmetro de objeto explícito do C++ 23. Isso deve funcionar:

    constexpr auto get_n = []<std::size_t N>
      (this auto self, /*tuple-like*/auto&& t, std::size_t index)
    {
        using variant_type = decltype(std::apply([](auto&&... v){
            return std::variant<std::monostate, std::remove_cvref_t<decltype(v)>...>{};
        }, t));
    
        constexpr auto size = std::tuple_size_v<std::remove_cvref_t<decltype(t)>>;
    
        if constexpr(N > size)
            return variant_type{};
        else 
        {
            if(N == index + 1)
                return variant_type(std::in_place_index<N>, std::get<N - 1>(t));
            else
                return self.template operator()<N + 1>(t, index);
        }
    };
    
    constexpr auto tuple_to_variant(/*tuple-like*/auto&& t, std::size_t index)
    {
        return get_n.operator()<1>(std::forward<decltype(t)>(t), index);
    }
    

    Demonstração

    • 2
  2. Best Answer
    LHLaurini
    2024-07-06T08:54:02+08:002024-07-06T08:54:02+08:00

    Funciona se você usar

    template<std::size_t N>
    constexpr auto get_n(/*tuple-like*/auto&& t, std::size_t index)
    

    em vez de. Não há razão para get_nser um lambda.

    • 1
  3. Gene
    2024-07-06T11:44:06+08:002024-07-06T11:44:06+08:00

    E esta é outra solução possível aceita por todo compilador. A vantagem é que a função lambda é local tuple_to_variant, portanto não cria nenhum nome no escopo externo.

    inline auto tuple_to_variant(auto&& t, std::size_t index)
    {
        constexpr auto get_n = []<auto N>(this auto&& self, auto&& t, std::size_t index, std::index_sequence<N>)
        {
            using variant_type = decltype(std::apply([](auto&&... v){
                return std::variant<std::monostate, std::remove_cvref_t<decltype(v)>...>{};
            }, t));
    
            constexpr auto size = std::tuple_size_v<std::remove_cvref_t<decltype(t)>>;
    
            if constexpr(N > size)
                return variant_type{};
            else 
            {
                if(N == index + 1)
                    return variant_type(std::in_place_index<N>, std::get<N - 1>(t));
                else
                    return self(t, index, std::index_sequence<N + 1>{});
            }
        };
    
        return get_n(std::forward<decltype(t)>(t), index, std::index_sequence<1>{});
    }
    

    Demonstração do Explorador de Código

    • 0
  4. Red.Wave
    2024-07-06T19:30:11+08:002024-07-06T19:30:11+08:00

    Uma implementação não recursiva com tipos detalhados seria:

    constexpr auto tuple_to_variant(std::size_t i, auto && t)
    {
        using ref_t = decltype(t);
        using tuple = std::remove_cvref_t<ref_t>;
        constexpr std::tuple_size<tuple> size;
        return [&t]<std::size_t ... j>
        (std::index_sequence<j ...>, auto i) {
              using variant = std::variant
                            < std::monostate
                            , std::remove_cvref_t
                            < std::tuple_element_t<j, tuple> > ...>;
              constexpr std::array dispatch {
                  +[](ref_t&) { return variant{}; },
                  +[](ref_t& lvalue_) {
                  return variant 
                       { std::in_place_index<1 + j>
                       , get<j>(static_cast<ref_t>(lvalue_)) };
                  }...
              };// dispatch;
              return dispatch[i](t);
        }(make_index_sequence<size()>{}
        , i >= size() ? 0 : 1 + i);
    };// tuple_to_variant;
    

    Eu gosto de colocar o argumento ativo/operacional/de seleção ( i) primeiro e o argumento passivo ( t) por último.

    • 0

relate perguntas

  • Por que os compiladores perdem a vetorização aqui?

  • Erro de compilação usando CMake com biblioteca [fechada]

  • Erro lançado toda vez que tento executar o premake

  • Como criar um tipo de octeto semelhante a std::byte em C++?

  • Somente operações bit a bit para std::byte em C++ 17?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Por que esse código Java simples e pequeno roda 30x mais rápido em todas as JVMs Graal, mas não em nenhuma JVM Oracle?

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Quando devo usar um std::inplace_vector em vez de um std::vector?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Marko Smith

    Estou tentando fazer o jogo pacman usando apenas o módulo Turtle Random e Math

    • 1 respostas
  • Martin Hope
    Aleksandr Dubinsky Por que a correspondência de padrões com o switch no InetAddress falha com 'não cobre todos os valores de entrada possíveis'? 2024-12-23 06:56:21 +0800 CST
  • Martin Hope
    Phillip Borge Por que esse código Java simples e pequeno roda 30x mais rápido em todas as JVMs Graal, mas não em nenhuma JVM Oracle? 2024-12-12 20:46:46 +0800 CST
  • Martin Hope
    Oodini Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores? 2024-12-12 06:27:11 +0800 CST
  • Martin Hope
    sleeptightAnsiC `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso? 2024-11-09 07:18:53 +0800 CST
  • Martin Hope
    The Mad Gamer Quando devo usar um std::inplace_vector em vez de um std::vector? 2024-10-29 23:01:00 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST
  • Martin Hope
    MarkB Por que o GCC gera código que executa condicionalmente uma implementação SIMD? 2024-02-17 06:17:14 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve