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 / 78428407
Accepted
Jan Schultke
Jan Schultke
Asked: 2024-05-04 17:05:20 +0800 CST2024-05-04 17:05:20 +0800 CST 2024-05-04 17:05:20 +0800 CST

std::ranges::transform_view::iterator não é um InputIterator?

  • 772

Eu tenho o seguinte código ( https://godbolt.org/z/K7sPbjjKE ):

#include <string>
#include <ranges>
#include <vector>

std::vector<std::string> fields;

void insert_many(std::size_t pos, std::span<std::string> keys)
{
    auto view = std::views::iota(0uz, keys.size())
      | std::views::transform([&](std::size_t i) {
        return std::move(keys[i]);
    });
    static_assert(std::ranges::input_range<decltype(view)>);
    fields.insert(fields.cbegin() + pos, view.begin(), view.end());
}

Nota: Este exemplo é simplificado demais em https://godbolt.org/z/hYTjsohTf . Eu sei, você não precisa usar std::views::iotanada aqui. A questão é por que o código em sua forma atual não funciona.

Tanto no libc++ quanto no libstdc++, os static_assertpasses. No entanto, apenas libc++ permite a chamada para insert. estou tentando ligar

template< class InputIt >
constexpr iterator insert( const_iterator pos, InputIt first, InputIt last );

Pela aparência da mensagem de erro (com libstdc++), std::ranges::transform_view::iteratornão satisfaz InputIterator , portanto a sobrecarga não pode ser chamada:

/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/15.0.0/../../../../include/c++/15.0.0/bits/stl_vector.h:1484:2: note: candidate template ignored: requirement 'is_convertible<std::output_iterator_tag, std::input_iterator_tag>::value' was not satisfied [with >  _InputIterator = _Iterator<false>]
 1484 |         insert(const_iterator __position, _InputIterator __first,
      |         ^

Esse é o comportamento pretendido? Achei que o novo std::viewsmaterial também satisfazia os requisitos do iterador legado.

c++
  • 3 3 respostas
  • 83 Views

3 respostas

  • Voted
  1. Best Answer
    cpplearner
    2024-05-04T18:51:32+08:002024-05-04T18:51:32+08:00

    Tanto libstdc++ quanto libc++ estão corretos. O código em questão depende simplesmente de um comportamento não especificado e, portanto, não é portátil.

    1. O tipo de diferença std::views::iota(0uz, keys.size())deve ser IOTA-DIFF-T(size_t), que é um tipo de número inteiro assinado não especificado ( [range.iota.view]/(1.3) ).
    2. Um tipo de número inteiro assinado é um signed_integraltipo ou um tipo de classe de número inteiro assinado ( [iterator.concept.winc]/4 ).
    3. Um tipo de classe inteira faz parte de um conjunto de tipos definidos pela implementação (( [iterator.concept.winc]/2 ) que suporta operações inteiras.

    Ou seja, o padrão não exige std::views::iota(0uz, keys.size())ser um tipo inteiro.

    Como o tipo de diferença de a transform_viewé o mesmo de sua visão subjacente, também não é necessário que seja um tipo inteiro. Assim, libstdc++ está correto ao usar o específico da implementação __int128como o tipo de diferença.

    Por outro lado, como o padrão não proíbe o uso do tipo inteiro, libc++ também está correto.

    • 3
  2. Patrick Roberts
    2024-05-04T18:21:37+08:002024-05-04T18:21:37+08:00

    libc++ está correto, mas acho que isso deve ser considerado um bug do libstdc++, embora atenda tecnicamente aos requisitos de P1522 .

    std::vector::insertrequer que InputItseja um LegacyInputIterator :

    template <class T>
    concept __Referenceable = std::same_as<T&, std::add_lvalue_reference_t<T>>;
    
    template <class I>
    concept __LegacyIterator = requires(I i) {
      { *i } -> __Referenceable;
      { ++i } -> std::same_as<I&>;
      { *i++ } -> __Referenceable;
    } && std::copyable<I>;
    
    template <class I>
    concept __LegacyInputIterator =
        __LegacyIterator<I> && std::equality_comparable<I> && requires(I i) {
          typename std::incrementable_traits<I>::difference_type;
          typename std::indirectly_readable_traits<I>::value_type;
          typename std::common_reference_t<
              std::iter_reference_t<I>&&,
              typename std::indirectly_readable_traits<I>::value_type&>;
          *i++;
          typename std::common_reference_t<
              decltype(*i++)&&,
              typename std::indirectly_readable_traits<I>::value_type&>;
          requires std::signed_integral<
              typename std::incrementable_traits<I>::difference_type>;
        };
    
    ...
    
    static_assert(__LegacyInputIterator<decltype(view.begin())>);
    

    falha ao compilar com o seguinte erro em libstdc++:

    <source>:38:17: error: static assertion failed
       38 |   static_assert(__LegacyInputIterator<decltype(view.begin())>);
          |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    <source>:38:17: note: because 'decltype(view.begin())' (aka '_Iterator<false>') does not satisfy '__LegacyInputIterator'
    <source>:27:16: note: because 'typename std::incrementable_traits<_Iterator<false>>::difference_type' (aka '__int128') does not satisfy 'signed_integral'
    

    Olhando para std::is_integral, permite:

    quaisquer tipos inteiros estendidos definidos pela implementação

    Neste ponto, podemos concluir que para permitir o uso __int128de difference_typeum LegacyInputIterator , libstdc++ deve __int128ser considerado um número inteiro assinado.

    Por curiosidade, adicionei as duas especializações de modelo de valor a seguir (estou ciente de que isso é considerado UB):

    template <>
    inline constexpr bool std::is_integral_v<__int128> = true;
    
    template <>
    inline constexpr bool std::is_signed_v<__int128> = true;
    

    e isso permite que o código original seja compilado.

    Mudar std::views::iota(0uz, keys.size())para std::views::iota(0u, static_cast<unsigned>(keys.size()))também permite que o código seja compilado e não é UB, mas também não é uma solução alternativa muito satisfatória para esse problema.

    • 1
  3. sukhman matta
    2024-05-04T18:38:26+08:002024-05-04T18:38:26+08:00

    O problema aqui é que o tipo de iterador produzido por std::views::transform não é exatamente o que a função de inserção espera. Ele precisa de um iterador de entrada, mas o que está sendo gerado é mais parecido com um iterador direto.

    Para contornar isso, precisamos converter explicitamente os iteradores da visualização em iteradores de entrada usando std::ranges::begin e std::ranges::end. Dessa forma, temos certeza de que a função insert aceitará o intervalo corretamente.

    • -3

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