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 / user-5825294

Enlico's questions

Martin Hope
Enlico
Asked: 2025-04-25 05:49:56 +0800 CST

No contexto do STM, como é conceitualmente um log de transações e como ele evolui quando a transação é bem-sucedida após algumas tentativas?

  • 6

Por exemplo, considere esta função, que poderia ser usada em um WM para permitir mover uma janela de uma área de trabalho para outra em uma determinada tela,

moveWindowSTM :: Display -> Window -> Desktop -> Desktop -> STM ()
moveWindowSTM disp win a b = do
  wa <- readTVar ma
  wb <- readTVar mb
  writeTVar ma (Set.delete win wa)
  writeTVar mb (Set.insert win wb)
 where
  ma = disp ! a
  mb = disp ! b

e obviamente seu IOinvólucro,

moveWindow :: Display -> Window -> Desktop -> Desktop -> IO ()
moveWindow disp win a b = atomically $ moveWindowSTM disp win a b

e então assumir que

  • nossa transação é bem-sucedida na terceira tentativa,
  • porque na primeira tentativa ele é invalidado por outra transação simultânea sendo confirmada que altera o valor interno malogo após o término wa <- readTVar mada nossa transação,
  • e na segunda tentativa ele é invalidado por outra transação simultânea que altera o conteúdo de uma ou ambas as transações mae mblogo depois writeTVar ma (Set.delete win wa)da nossa transação.

Como o log de transações evoluiria nesse caso e em que ponto a validação falharia?

O trecho relevante de Parallel and Concurrent Programming in Haskell de Simon Marlow está abaixo (mas informações semelhantes estão disponíveis no artigo Beautiful concurrency de Simon Peyton Jones):

Uma transação STM funciona acumulando um log de readTVaroperações writeTVarque ocorreram até o momento durante a transação. O log é usado de três maneiras:

  • Ao armazenar writeTVaras operações no log em vez de aplicá-las imediatamente à memória principal, descartar os efeitos de uma transação é fácil; simplesmente descartamos o log. Portanto, abortar uma transação tem um custo fixo pequeno.

  • Cada um readTVardeve percorrer o log para verificar se o TVarfoi escrito por um writeTVar. Portanto, readTVaré uma operação O(n) no comprimento do log.

  • Como o log contém um registro de todas as readTVaroperações, ele pode ser usado para descobrir o conjunto completo de TVarsleituras durante a transação, o que precisamos saber para implementar retry.

Quando uma transação chega ao fim, a implementação do STM compara o log com o conteúdo da memória. Se o conteúdo atual da memória corresponder aos valores lidos por readTVar, os efeitos da transação são confirmados na memória; caso contrário, o log é descartado e a transação é executada novamente desde o início. Esse processo ocorre atomicamente, bloqueando todos os TVarsenvolvidos na transação durante sua duração. A implementação do STM no GHC não utiliza bloqueios globais; apenas os TVarsenvolvidos na transação são bloqueados durante o commit, de modo que transações que operam em conjuntos disjuntos de TVarspodem prosseguir sem interferência.

haskell
  • 2 respostas
  • 83 Views
Martin Hope
Enlico
Asked: 2025-04-24 14:30:40 +0800 CST

Por que a pesquisa de nome não qualificado de um nome dependente não encontra um lambda declarado entre a declaração do modelo e a instanciação?

  • 10

O programa a seguir está incorreto ,

inline constexpr auto makeFoo = [](auto const& x) {
    return getFoo(x);
};

inline constexpr auto getFoo = [](int const&) {
    return 1;
};

int bar() {
    return makeFoo(32);
}

e reverter as definições de makeFooe getFootorna-o correto .

Entendo que, com base no entendimento "informal" da pesquisa de nomes em duas fases:

  • makeFooé um lambda genérico e, getFooem seu corpo, é invocado em um argumento cujo tipo ainda não é conhecido, então o nome getFooainda não pode ser consultado;
  • quando a chamada makeFoo(32)é vista, o lambda operator()é intantiado com auto = int, então a busca de segunda fase pelo nome não qualificado getFooacontece;
  • isso, no entanto, é apenas ADL, então não encontra getFoo, porque esse é o nome de um lambda, ou seja, um objeto, não de uma função.

Alguém pode me orientar sobre as partes do rascunho padrão que "espelham" a explicação acima?

Suponho que [basic.lookup.unqual] e [temp.dep.res] possivelmente contenham tudo o que é necessário para explicar o caso, mas não consigo juntar as peças.

c++
  • 2 respostas
  • 179 Views
Martin Hope
Enlico
Asked: 2025-04-21 21:30:49 +0800 CST

Como a garantia de imparcialidade do GHC pode não aparecer se um thread for desagendado enquanto não estiver segurando o MVar?

  • 7

Em Programação Paralela e Concorrente em Haskell , de Simon Marlow, o capítulo 7 começa na página 125 com este exemplo,

import Control.Concurrent
import Control.Monad
import System.IO

main :: IO ()
main = do
  hSetBuffering stdout NoBuffering
  _ <- forkIO (replicateM_ 100000 (putChar 'A'))
  replicateM_ 100000 (putChar 'B')

que tem uma saída como esta

BBBBBBBABABABAAAAAAA

(que, aliás, é o resultado que realmente obtive ao alterar 100000para 10o snippet acima e executar o programa).

No final do capítulo, página 140, é feito o seguinte comentário (grifo meu):

[…] Este é um exemplo da garantia de imparcialidade na prática. […]. Portanto, isso leva à alternância perfeita entre as duas threads. A única maneira de o padrão de alternância ser quebrado é se uma thread for desescalonada enquanto não estiver segurando o MVar. De fato, isso acontece de tempos em tempos como resultado da preempção, e ocasionalmente vemos uma longa sequência de uma única letra na saída.

Com base no resultado que mostrei, sim, consigo ver que a alternância está quebrada, mas não entendi bem a explicação acima. Não há nem um MVarno primeiro exemplo.

haskell
  • 1 respostas
  • 54 Views
Martin Hope
Enlico
Asked: 2025-04-21 21:12:35 +0800 CST

Esclarecimento sobre a importância da imutabilidade do estado dentro de um MVar no contexto de concorrência

  • 6

Em Programação Paralela e Concorrente em Haskell , de Simon Marlow, nas páginas 133 e 134, o seguinte código é mostrado:

type Name        = String
type PhoneNumber = String
type PhoneBook   = Map Name PhoneNumber

newtype PhoneBookState = PhoneBookState (MVar PhoneBook)

lookup :: PhoneBookState -> Name -> IO (Maybe PhoneNumber)
lookup (PhoneBookState m) name = do
  book <- takeMVar m
  putMVar m book
  return (Map.lookup name book)

E na página seguinte, algumas observações. A parte final do segundo parágrafo me intriga um pouco. Aqui está a primeira metade do parágrafo:

Usar estruturas de dados imutáveis ​​em um wrapper mutável traz outros benefícios. Observe que, na lookupoperação, simplesmente capturamos o valor atual do estado e, em seguida, a Map.lookupoperação complexa ocorre fora da sequência takeMVar/ putMVar. Isso é bom para a concorrência, pois significa que o bloqueio é mantido apenas por um período muito curto.

Isso é bastante claro para mim, no sentido de que entendo que isso takeMVarcoloca o bloqueio e putMVaro libera imediatamente, de modo que os acessos simultâneos subsequentes ao PhoneBookStatenão sejam mais prejudicados. Ao mesmo tempo, também vejo que outras mutações do MVarsão possíveis, então, quando o tempo lookupretorna com um Just smth, esse (name, smth)par pode ter sido removido do mapa (ou, se retornou Nothing, alguns (name, smth)podem ter sido adicionados ao mapa).

Entretanto, não entendi o que a seguinte parte do parágrafo tenta transmitir:

Isso só é possível porque o valor do estado é imutável. Se a estrutura de dados fosse mutável, teríamos que manter o bloqueio enquanto operávamos nela.⁵


⁵. A outra opção é usar um algoritmo sem bloqueios, que é extremamente complexo e difícil de acertar.

O que isso significa? O autor está se referindo ao caso que Mapexpôs alguma API a uma mutação? Isso nem é possível, a menos que estejamos em IO, certo? Ou ele está se referindo a mutações realizadas no mconteúdo de (por outras threads após putMVara liberação do bloqueio) que de alguma forma afetaram booko conteúdo de ?

haskell
  • 2 respostas
  • 58 Views
Martin Hope
Enlico
Asked: 2025-04-19 19:25:32 +0800 CST

Por que o primeiro argumento do colchete deve executar no máximo uma operação de bloqueio?

  • 7

Em Programação Paralela e Concorrente em Haskell de Simon Marlow, a implementação de bracketé mostrada,

bracket
        :: IO a         -- ^ computation to run first (\"acquire resource\")
        -> (a -> IO b)  -- ^ computation to run last (\"release resource\")
        -> (a -> IO c)  -- ^ computation to run in-between
        -> IO c         -- returns the value from the in-between computation
bracket before after thing =
  mask $ \restore -> do
    a <- before
    r <- restore (thing a) `onException` after a
    _ <- after a
    return r

e um comentário segue. Aqui está a parte que está me intrigando

[…] É normal que beforecontenha uma operação de bloqueio; se uma exceção for gerada enquanto beforeestiver bloqueado, não haverá danos. Mas beforedeve executar apenas uma operação de bloqueio. Uma exceção gerada por uma segunda operação de bloqueio não resultaria em afterexecução. […]

Não entendi bem esse comentário, então gostaria de alguns esclarecimentos sobre ele.

Para esclarecer, não entendi nem a parte de que nenhum dano é causado : algumas páginas antes (p. 159), a seguinte tentativa falhada (segunda) de chamar takeMVar, executar uma operação dependendo de seu conteúdo e, finalmente, colocar o resultado dessa operação de volta na MVarvia putMVaré mostrada,

problem :: MVar a -> (a -> IO a) -> IO ()
problem m f = mask $ \restore -> do
  a <- takeMVar m
  r <- restore (f a) `catch`  \e -> do putMVar m a; throw e
  putMVar m r

Ao analisar este exemplo, "aceito" como um fato que takeMVarnão pode ser alterado maté que retorne; na verdade, isso foi retirado do texto:

seria seguro que exceções fossem levantadas até o ponto em que takeMVarretornasse.

e sinto que entendo o que se segue (eu acho ).

Mas voltando à implementação de bracket, e se beforeinternamente usar takeMVar, e uma exceção assíncrona ocorrer após o takeMVarretorno dela (esvaziando um MVar)? Isso não é um problema, justamente pelo motivo de estarmos usando mask+ restore, ou seja, tal exceção seria adiada até que o argumento para restore, que é thing a, comece a ser executado, momento em que o manipulador de exceções necessário está em vigor, neste caso via `onException` after a?

E o que dá errado se beforefizer outra chamada para a operação de bloqueio, digamos takeMVarnovamente para simplificar? O problema ocorre porque a exceção poderia ocorrer enquanto takeMVar o bloqueio estiver em andamento, portanto, na janela de tempo em que as exceções não são mascaradas, de modo que a exceção sairia de bracket, deixando o MVarargumento that was para o primeiro takeMVarnão vazio, mas em um estado diferente do original, dado que afternão teve a chance de ser executado?

É isso?

Além disso, a página do documento não menciona isso, ou não vejo como isso está implícito.

exception
  • 1 respostas
  • 91 Views
Martin Hope
Enlico
Asked: 2025-02-08 18:13:37 +0800 CST

O comportamento dessas duas funções difere de alguma forma que justifique o GHC compilá-las em códigos de objeto diferentes?

  • 5

Aqui está um módulo:

module Foo where

foo ws = let ws' = take 3 $ ws ++ repeat mempty
             x = ws' !! 0
             y = ws' !! 1
             z = ws' !! 2
         in [x, y, z]

e aqui vai mais um

module Foo where

foo ws = let (x:y:z:_) = take 3 $ ws ++ repeat mempty
         in [x, y, z]

Via ghc -O2 -c foo.hs, eles compilam para 8072 e 5288 bytes, respectivamente. Não tenho certeza de qual é o melhor, nem como testá-los, mas acho que eles não podem se comportar de forma idêntica, em termos de desempenho, simplesmente porque são diferentes.

As duas funções se comportam de forma diferente? Se não, a diferença no binário gerado é devido a uma otimização perdida? Ou o quê?

haskell
  • 1 respostas
  • 57 Views
Martin Hope
Enlico
Asked: 2024-12-28 14:03:08 +0800 CST

Instância de typeclass IO falsa é encontrada no código de produção, mas não no teste

  • 7

Tenho muitas IOações baseadas em , sendo uma das mais simples a seguinte:

-- Loop.hs
module Loop where
import System.Console.ANSI (setCursorPosition)
type Pos = (Int, Int)
setCursorPosition' :: Pos -> IO ()
setCursorPosition' = uncurry setCursorPosition

Nesse ponto, partindo do exposto acima, decidi escrever essas funções em termos de uma restrição de tipo implementada por IO, em vez de codificar IO, como sugerido por esta resposta .

Então o que eu fiz consistiu em

  • definindo um FakeIOtipo classe sua implementação trivial para IO:
    -- Interfaces.hs
    module Interfaces where
    import qualified System.Console.ANSI as ANSI (setCursorPosition)
    
    class FakeIO m where
      setCursorPosition :: Int -> Int -> m ()
    
    instance FakeIO IO where
      setCursorPosition = ANSI.setCursorPosition
    
  • alterado setCursorPosition'para usar esta interface:
    -- Loop.hs
    module Loop where
    import Interfaces
    type Pos = (Int, Int)
    setCursorPosition' :: FakeIO m => Pos -> m ()
    setCursorPosition' = uncurry setCursorPosition
    

Isso fez com que o programa continuasse funcionando bem (via cabal run), atestando que a "refatoração" estava correta.

Mas quando tentei alavancar essa refatoração para fins de teste, fiquei preso. O que fiz foi escrever o seguinte teste:

-- test/Main.hs
module Main where

import Control.Monad (unless)
import System.Exit (exitFailure)
import MTLPrelude (State, execState, modify')
import Test.QuickCheck

import Loop
import Interfaces

data MockTerminal = MockTerminal {
  pos :: (Int, Int)
} deriving Eq

instance FakeIO (State MockTerminal) where
  setCursorPosition y x = modify' $ \m -> MockTerminal { pos = (y, x) }

main :: IO ()
main = do
  result <- quickCheckResult tCenter
  unless (isSuccess result) exitFailure

tCenter :: Bool
tCenter = (setCursorPosition' (1,1))
          `execState` MockTerminal { pos = (0,0)}
          == MockTerminal { pos = (1,1) }

que falha ao compilar (via cabal test) porque

error: [GHC-39999]
    • No instance for ‘snakegame-0.1.0.0:Loop:Interfaces.FakeIO
                         (StateT MockTerminal Identity)’
        arising from a use of ‘setCursorPosition'’
    • In the first argument of ‘execState’, namely
        ‘(setCursorPosition' (1, 1))’
      In the first argument of ‘(==)’, namely
        ‘(setCursorPosition' (1, 1))
           `execState` MockTerminal {pos = (0, 0)}’
      In the expression:
        (setCursorPosition' (1, 1)) `execState` MockTerminal {pos = (0, 0)}
          == MockTerminal {pos = (1, 1)}
   |
41 | tCenter = (setCursorPosition' (1,1))
   |            ^^^^^^^^^^^^^^^^^^

o que eu não entendo, porque instance FakeIO (State MockTerminal)deveria ser exatamente a snakegame-0.1.0.0:Loop:Interfaces.FakeIO (StateT MockTerminal Identity)instância que o compilador está alegando que não existe.

Além disso, se eu alterar o teste para usar setCursorPosition 1 1em vez de setCursorPosition' (1,1), ele compila e passa, revelando que o instanceestá realmente fazendo seu trabalho.

Então deve haver algo errado com a forma como isso instancese integra à definição de setCursorPosition'.


Reduzi o exemplo para os 4 arquivos a seguir:

$ tree !(dist-newstyle)
cabal.project  [error opening dir]
LICENSE  [error opening dir]
Session.vim  [error opening dir]
snakegame.cabal  [error opening dir]
src
├── Interfaces.hs
├── Loop.hs
└── Main.hs
test
└── Main.hs

2 directories, 8 files

dos quais:

-- src/Main.hs
module Main where

import Loop

main :: IO ()
main = setCursorPosition' (1,1)
-- src/Loop.hs
module Loop (setCursorPosition') where

import Interfaces
type Pos = (Int, Int)

setCursorPosition' :: FakeIO m => Pos -> m ()
setCursorPosition' = uncurry setCursorPosition
-- test/Main.hs
module Main where

import Control.Monad (unless)
import System.Exit (exitFailure)
import MTLPrelude (State, execState, modify')
import Test.QuickCheck

import Loop
import Interfaces

data MockTerminal = MockTerminal {
  pos :: (Int, Int)
} deriving Eq

instance FakeIO (State MockTerminal) where
  setCursorPosition y x = modify' $ \m -> MockTerminal { pos = (y, x) }
  putChar _ = modify' id

main :: IO ()
main = do
  result <- quickCheckResult tCenter
  unless (isSuccess result) exitFailure

tCenter :: Bool
tCenter = (setCursorPosition' (1,1))
          `execState` MockTerminal { pos = (0,0)}
          == MockTerminal { pos = (1,1)}
cabal-version: 3.0
name: snakegame
version: 0.1.0.0

common common
    default-language: GHC2024
    build-depends: base >= 4.19.1.0
                 , ansi-terminal
                 , mtl-prelude

common warnings
    ghc-options: -Wall

executable snakegame
    import: warnings, common
    main-is: Main.hs
    other-modules: Loop
                 , Interfaces
    hs-source-dirs: src

library Loop
    import: warnings, common
    exposed-modules: Loop
    hs-source-dirs: src

library Interfaces
    import: warnings, common
    exposed-modules: Interfaces
    hs-source-dirs: src

test-suite Test
    import: warnings, common
    type: exitcode-stdio-1.0
    main-is: Main.hs
    build-depends: QuickCheck
                 , Interfaces
                 , Loop
    hs-source-dirs: test
packages: .

with-compiler: ghc-9.10.1
unit-testing
  • 1 respostas
  • 54 Views
Martin Hope
Enlico
Asked: 2024-12-27 14:16:31 +0800 CST

Nada gerado pela execução de uma pilha de transformadores de mônadas não é == Nada?

  • 7

Reproduções:

cabal repl --build-depends=mtl-prelude,transformers
λ> import Data.Mayb
λ> import Control.Monad
λ> import Control.Monad.Trans.Identity
λ> import MTLPrelude
λ> :{
ghci| maybeQuit :: MonadPlus m => Maybe Char -> MaybeT m (Maybe Char)
ghci| maybeQuit key = do
ghci|   case key of
ghci|     Just 'q' -> mzero
ghci|     Just '\ESC' -> mzero
ghci|     _ -> return key
ghci| :}
λ> runIdentityT $ runMaybeT $ maybeQuit (Just 'c')
Just (Just 'c')
λ> runIdentityT $ runMaybeT $ maybeQuit (Just 'q')
Nothing

Até agora tudo bem.

Mas então:

λ> (runIdentityT $ runMaybeT $ maybeQuit (Just 'q')) == Nothing 
False
λ> isNothing (runIdentityT $ runMaybeT $ maybeQuit (Just 'q'))
False

O que?!


Eu vejo que a expressão é um pouco polimórfica,

λ> :t runIdentityT $ runMaybeT $ maybeQuit (Just 'q')
runIdentityT $ runMaybeT $ maybeQuit (Just 'q')
  :: MonadPlus f => f (Maybe (Maybe Char))

mas não tenho certeza de como isso pode implicar que algo impresso como Nothingpoderia ser diferente de (==) Nothing.


Para contextualizar, estou executando maybeQuitem uma pilha monádica (há MaybeTe outros transformadores nela) com um IOna parte inferior, e está funcionando como esperado, mas suas implementações, portanto o tipo, não requerem o poder de IO, então eu estava tentando testá-lo em uma mônada diferente de IO, e foi assim que cheguei a fazer essa pergunta.

Em retrospecto, começo a ver outra coisa que não entendo muito bem: vejo :t runMaybeT $ maybeQuit (Just 'q')is MonadPlus m => m (Maybe (Maybe Char)), que é o que espero, mas, ao aplicar runIdentityTa isso, obtenho o tipo MonadPlus f => f (Maybe (Maybe Char), que é a mesma coisa, então devo estar entendendo mal o significado/propósito de IdentityT, e não consigo deixar de pensar que essa é a razão pela qual não obtenho o que acho que deveria obter no exemplo original.

À luz do raciocínio acima, tentei forçar m === []a expressão runMaybeT $ maybeQuit (Just 'c')aplicando- heada a ela, e o resultado é mais o que eu esperava:

λ> isNothing (head $ runMaybeT $ maybeQuit (Just 'q'))
True
λ> isNothing (head $ runMaybeT $ maybeQuit (Just 'c'))
False

mas ainda não entendi o que há de errado em usar runIdentityT.

haskell
  • 1 respostas
  • 45 Views
Martin Hope
Enlico
Asked: 2024-12-16 23:33:09 +0800 CST

(Como) posso obter o caractere que está sendo exibido atualmente em uma determinada posição no terminal?

  • 7

(Relacionado a uma pergunta anterior .)

Se eu puder imprimir um caractere no terminal via Prelude.putCharem uma posição que eu decidi via System.Console.ANSI.setCursorPosition, como posso obter o caractere nessa posição?

O caso de uso é que eu quero fazer algo assim

do
  setCursorPosition a b
  c <- getTheCharacterHere
  putChar $ if c == 'x' then 'y' else 'z'

onde getTheCharacterHereé a ação desejada para recuperar o caractere atualmente mostrado na posição definida via setCursorPosition.

haskell
  • 1 respostas
  • 42 Views
Martin Hope
Enlico
Asked: 2024-11-30 00:46:21 +0800 CST

Chamar fun não-const mem. em objeto const via ref não-const obtido via const_cast invoca UB somente se o fun realmente modifica o objeto? [duplicado]

  • 5
Esta pergunta já tem uma resposta aqui :
É permitido lançar const em um objeto definido por const, desde que ele não seja realmente modificado? (1 resposta)
Fechado há 21 horas .

Resumindo, estou perguntando se o código a seguir invoca o UB somente se /* body */de fato altera o valor de i, ou também se não altera, em virtude da chamada da const maybeChangefunção não membro em um constobjeto.

// header.hpp
struct Foo {
  int i;
  void maybeChange();
};

void work(Foo const& foo);
// foo.cpp
#include "header.hpp"
void Foo::maybeChange() {
  /* body */
}
// work.cpp
#include "header.hpp"
void work(Foo const& foo) {
  const_cast<Foo&>(foo).maybeChange();
}
// main.cpp
#include "header.hpp"
Foo const foo{6};

int main() {
  work(foo);
}

Vejo que o problema existe caso a modificação realmente ocorra, porque isso viola uma suposição legítima que o compilador pode fazer, ou seja, que o fooobjeto global não muda.

Mas, por outro lado, http://eel.is/c++draft/dcl.type.cv#4 não mostra nenhum exemplo de chamada de constfunção não membro em constobjeto para o qual constfoi const_casted away, mas isso não o modifica de fato, como no meu exemplo acima. Ele mostra exemplos triviais como

const int* ciq = new const int (3);     // initialized as required
int* iq = const_cast<int*>(ciq);        // cast required
*iq = 4;                                // undefined behavior: modifies a const object

onde a última linha realmente modifica o objeto *ciq.

c++
  • 1 respostas
  • 69 Views
Martin Hope
Enlico
Asked: 2024-11-18 18:30:55 +0800 CST

Como verificar em tempo de compilação a existência de uma função de escopo global que aceita determinados tipos de argumentos?

  • 13

O que (eu acho) eu preciso

Como posso definir uma característica de tipo que verifica se, para um tipo T, a função ::foo(T)é declarada?

O que estou achando difícil é ter ::foouma maneira amigável ao SFINAE. Por exemplo, se o compilador chegou ao ponto em que o seguinte é definido,

template<typename T>
void f(T t) { foo(t); }

está tudo bem se nada foofoi visto até agora.

Mas assim que mudo foopara ::foo, recebo um erro grave.

O caso de uso (caso você ache que não preciso do acima)

Tenho um ponto de personalização como este:

// this is in Foo.hpp
namespace foos {
inline constexpr struct Foo {
    template <typename T, std::enable_if_t<AdlFooable<std::decay_t<T>>::value, int> = 0>
    constexpr bool operator()(T const& x) const {
        return foo(x);
    }
} foo{};
}

que permite personalizar o comportamento de uma chamada foos::foodefinindo uma foosobrecarga ADL para o tipo desejado.

A definição da característica é simples:

// this is in Foo.hpp
template <typename T, typename = void>
struct AdlFooable : std::false_type {};

template <typename T>
struct AdlFooable<T, std::void_t<decltype(foo(std::declval<T const&>()))>>
    : std::true_type {};

Dado que, se alguém define

// this is in Bar.hpp
namespace bar {
    struct Bar {};
    bool foo(bar::Bar);
}

então uma chamada para

// other includes
#include "Foo.hpp"
#include "Bar.hpp"
bool b = foos::foo(bar::Bar{});

funciona como esperado, com foos::fooroteamento da chamada para bar::foo(bar::Bar), que é encontrado via ADL. E isso funciona bem independentemente da ordem dos dois #includes, o que é bom, porque eles podem ser incluídos em qualquer ordem, se // other includestransitivamente os incluir.

Até agora tudo bem.

O que eu realmente não gosto dessa abordagem é que alguém poderia definir erroneamente, em vez do segundo trecho acima, o seguinte,

// this is in Bar.hpp
namespace bar {
    struct Bar {};
}
bool foo(bar::Bar);

com fooescopo global.

Nesse caso, se o #include "Bar.hpp"vier antes de #include "Foo.hpp", o programa de código funcionará, porque o corpo de Foo::operator()será selecionado ::foo(bar::Bar)por pesquisa comum.

Mas assim que a ordem do #includes é invertida, o código quebra.

Sim, o bug está na definição foo(bar::Bar)do namespace global, mas acho que também é um bug que pode passar despercebido por puro acaso.

É por isso que eu gostaria de mudar o traço de tipo para expressar que "uma chamada não qualificada para foo(T)é encontrada, mas não por meio de uma pesquisa comum " ou, mais diretamente, " foo(std::declval<T>())deve compilar, mas não::foo(std::declval<T>()) deve compilar" .

c++
  • 1 respostas
  • 235 Views
Martin Hope
Enlico
Asked: 2024-11-16 20:53:56 +0800 CST

std::ranges::enumerate pode enumerar qualquer array C++ válido possível?

  • 4

Uma vez perguntei se std::ranges::views::enumerateusa o tipo errado ( long) para indexação no GCC, mas aparentemente não é o caso , porque

std::views::enumerateé especificado para ser usado range_difference_t<Base>como seu valor de índice.

No entanto, a partir do rascunho

O tipo size_té um tipo inteiro sem sinal definido pela implementação que é grande o suficiente para conter o tamanho em bytes de qualquer objeto ( [expr.sizeof] ).

Portanto, pode-se pensar em uma matriz tão longa que os elementos finais de algum índice em diante não se encaixam no tipo usado para enumerateindexação, embora ainda se encaixem std::size_tpor definição, desde que em uma determinada máquina, o seguinte seja válido

static_assert(std::numeric_limits<std::size_t>::max() > std::numeric_limits<long>::max());

Por exemplo, tal matriz seria esta:

std::vector<int> v(std::numeric_limits<std::size_t>::max());

para o qual eu gostaria de saber como kevolui o seguinte:

auto w = v | std::ranges::views::enumerate;
for (auto [k, _] : w) {
    std::cout << k << std::endl;
}

Infelizmente, std::vectornão parece permitir esse tamanho de forma alguma, lançando exceções, enquanto um std::arraycom esse mesmo tamanho nem é compilável (exemplo completo aqui ), mas presumo que nenhum comportamento seja obrigatório pelo padrão. Ou é?

c++
  • 1 respostas
  • 63 Views
Martin Hope
Enlico
Asked: 2024-10-24 01:15:17 +0800 CST

Onde está o código binário para executar `std::vector<T>::operator[]`, quando uma TU que chama essa função é compilada com -O0?

  • 6

Se eu compilar o seguinte com-O3

#include <vector>
int foo() {
    std::vector<int> const v{17,2,3};
    return v[0] + v[2];
}

a montagem que eu recebo é

foo():
        mov     eax, 20
        ret

( pelo menos com Clang ).

E eu entendo como isso funcionaria quando chamado por alguma outra TU.

Mas se eu compilar com -O0, obtenho isto :

_Z3foov:
        pushq   %rbp
        movq    %rsp, %rbp
        subq    $112, %rsp
        movl    $17, -84(%rbp)
        movl    $2, -80(%rbp)
        movl    $3, -76(%rbp)
        leaq    -84(%rbp), %rax
        movq    %rax, -72(%rbp)
        movq    $3, -64(%rbp)
        leaq    -85(%rbp), %rcx
        movq    %rcx, -32(%rbp)
        movq    -32(%rbp), %rax
        movq    %rax, -8(%rbp)
        movq    -72(%rbp), %rsi
        movq    -64(%rbp), %rdx
        leaq    -56(%rbp), %rdi
        callq   _ZNSt6vectorIiSaIiEEC2ESt16initializer_listIiERKS0_
        jmp     .LBB0_1
.LBB0_1:
        leaq    -85(%rbp), %rax
        movq    %rax, -24(%rbp)
        leaq    -56(%rbp), %rdi
        xorl    %eax, %eax
        movl    %eax, %esi
        callq   _ZNKSt6vectorIiSaIiEEixEm
        movl    (%rax), %eax
        movl    %eax, -108(%rbp)
        leaq    -56(%rbp), %rdi
        movl    $2, %esi
        callq   _ZNKSt6vectorIiSaIiEEixEm
        movq    %rax, %rcx
        movl    -108(%rbp), %eax
        addl    (%rcx), %eax
        movl    %eax, -104(%rbp)
        leaq    -56(%rbp), %rdi
        callq   _ZNSt6vectorIiSaIiEED2Ev
        movl    -104(%rbp), %eax
        addq    $112, %rsp
        popq    %rbp
        retq
        movq    %rax, %rcx
        movl    %edx, %eax
        movq    %rcx, -96(%rbp)
        movl    %eax, -100(%rbp)
        leaq    -85(%rbp), %rax
        movq    %rax, -16(%rbp)
        movq    -96(%rbp), %rdi
        callq   _Unwind_Resume@PLT

__clang_call_terminate:
        pushq   %rbp
        movq    %rsp, %rbp
        callq   __cxa_begin_catch@PLT
        callq   _ZSt9terminatev@PLT

.L.str:
        .asciz  "cannot create std::vector larger than max_size()"

.L.str.1:
        .asciz  "/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/15.0.0/../../../../include/c++/15.0.0/bits/stl_vector.h"

.L__PRETTY_FUNCTION__._ZNKSt6vectorIiSaIiEEixEm:
        .asciz  "const_reference std::vector<int>::operator[](size_type) const [_Tp = int, _Alloc = std::allocator<int>]"

.L.str.2:
        .asciz  "__n < this->size()"

DW.ref.__gxx_personality_v0:
        .quad   __gxx_personality_v0

onde _ZNKSt6vectorIiSaIiEEixEmé chamado quando computando v[0]e v[2]. Mas eu realmente não entendo onde esses 2 calls saltam. Quer dizer, a string _ZNKSt6vectorIiSaIiEEixEmaparece apenas 3 vezes, 2 são o calls, e um é este:

.L__PRETTY_FUNCTION__._ZNKSt6vectorIiSaIiEEixEm:
        .asciz  "const_reference std::vector<int>::operator[](size_type) const [_Tp = int, _Alloc = std::allocator<int>]"

Como isso pode resultar na retirada dos elementos do vetor?

Ou, em outras palavras, se eu vincular a TU acima com outra que a chama e retorna o valor, por exemplo

int foo();
int main() {
  return foo();
}

onde encontro o código o código que executa v[0]e v[2]? Se não está no assembly, nem está no binário, certo? Então como o programa roda?

c++
  • 1 respostas
  • 47 Views
Martin Hope
Enlico
Asked: 2024-09-24 14:33:31 +0800 CST

Por que uma função que retorna apenas um lambda com estado é compilada em qualquer assembly?

  • 12

A seguinte função não-template (ou seria?) retornando um lambda não genérico e com estado,

auto foo(double a) {
    return [a](double b) -> double {
        return a + b;
    };
}

compilado para isso com GCC ou Clang . Por quê?

foo(double):
        ret

Eu esperaria que não gerasse nenhuma saída .


A origem da questão

Nem me lembro por que comecei a escrever o trecho acima, mas enfim...

Inicialmente pensei que deveria ter sido compilado para algo um pouco maior, pois esperava ver addpelo menos uma instrução.

Mas então percebi que o fooacima não pode ser compilado sozinho, em um cpp, e então vinculado a outra TU onde é usado, porque não consigo nem escrever uma declaração - somente para ele!

Então chego ao ponto em que a única razão para escrever essa função em um arquivo sem cabeçalho é que ela é usada nesse arquivo sem cabeçalho, e nesse ponto o compilador pode presumivelmente incorporá-la onde quer que ela seja usada.

Mas se esse é o caso... então por que copilar foopara baixo para qualquer coisa , se é a única coisa na TU? Não há nada para vincular, então por que qualquer saída é gerada para isso?


Usar um struct+ operator()não muda nada, pois isso

struct Bar {
    double a;
    double operator()(double b) const {
        return a + b;
    }
};

Bar bar(double a) {
    return Bar{a};
}

gera o mesmo retcódigo -only, o que também é óbvio em retrospecto, pois não há como vincular essa barfunção a outras TUs, se Barestiver oculta no arquivo cpp.

c++
  • 1 respostas
  • 304 Views
Martin Hope
Enlico
Asked: 2024-08-02 23:47:14 +0800 CST

O que determina qual versão do GHC (e Cabal, e HLS, ...) está marcada como "recomendada" no GHCup?

  • 8

Costumo me limitar às versões "recomendadas":

┌──────────────────────────────────GHCup──────────────────────────────────┐
│    Tool  Version         Tags                          Notes            │
│─────────────────────────────────────────────────────────────────────────│
│✔✔  GHCup 0.1.30.0   latest,recommended                                  │
│─────────────────────────────────────────────────────────────────────────│
│✗   Stack 2.15.7     latest                                              │
│✗   Stack 2.15.5     recommended                                         │
│✗   Stack 2.15.3                                                         │
│─────────────────────────────────────────────────────────────────────────│
│✗   HLS   2.9.0.1    latest                                              │
│✗   HLS   2.9.0.0                                                        │
│✗   HLS   2.8.0.0                                                        │
│✔✔  HLS   2.7.0.0    recommended                                         │
│✗   HLS   2.6.0.0                                                        │
│─────────────────────────────────────────────────────────────────────────│
│✗   cabal 3.12.1.0   latest                                              │
│✔✔  cabal 3.10.3.0   recommended                                         │
│✗   cabal 3.6.2.0-p1                                                     │
│─────────────────────────────────────────────────────────────────────────│
│✗   GHC   9.10.1     latest,base-4.20.0.0                                │
│✗   GHC   9.8.2      base-4.19.1.0                 hls-powered,2024-02-23│
│✗   GHC   9.6.6      base-4.18.2.1                                       │
│✗   GHC   9.6.5      base-4.18.2.1                                       │
│✔✔  GHC   9.4.8      recommended,base-4.17.2.1     hls-powered           │
│✗   GHC   9.2.8      base-4.16.4.0                 hls-powered           │
│✗   GHC   9.0.2      base-4.15.1.0                                       │
│✗   GHC   8.10.7     base-4.14.3.0                                       │
│✗   GHC   8.8.4      base-4.13.0.0                                       │
│✗   GHC   8.6.5      base-4.12.0.0                                       │
│✗   GHC   8.4.4      base-4.11.1.0                                       │
└─────────────────────────────────────────────────────────────────────────┘

No entanto, parece que estou tendo problemas para desenvolver o Hackage , e talvez seja porque o Hackage está usando um GHC mais recente do que aquele que o GHCup me diz ser a versão recomendada.

Então, qual é a relevância de “recomendado” e de onde ele vem?

haskell
  • 1 respostas
  • 33 Views
Martin Hope
Enlico
Asked: 2024-08-02 14:42:44 +0800 CST

Por que range::views::remove_if | ranges::to_vector e ranges::actions::remove_if geram código diferente? E qual devo preferir e por quê?

  • 7

Pegue isso

#include <range/v3/view/remove_if.hpp>
#include <range/v3/range/conversion.hpp>
#include <vector>

std::vector<int> foo(std::vector<int> v, bool(*p)(int)) {
    return v | ranges::views::remove_if(p) | ranges::to_vector;
}

em comparação com isso

#include <range/v3/action/remove_if.hpp>
#include <vector>

std::vector<int> bar(std::vector<int> v, bool(*p)(int)) {
    return std::move(v) | ranges::actions::remove_if(p);
}

Não há modelos disponíveis, apenas duas TUs fornecendo, cada uma, uma função pura com a mesma assinatura. Dada a sua implementação, esperaria que as duas funções realizassem a mesma tarefa, do ponto de vista do chamador. E é isso que eles parecem fazer.

No entanto, eles compilam em códigos bastante diferentes, a tal ponto que o GCC (tronco, pelo menos) produz código mais curto para o último, enquanto o Clang (tronco) produz código mais curto para o primeiro.

Não vejo nenhuma razão para as duas funções compilarem em códigos diferentes, a não ser "é muito difícil para o compilador criar o mesmo código para ambos" , mas o que está tornando isso tão difícil? Ou, se estiver errado, por que as duas funções devem ser compiladas em assembly diferente?

E, além do benchmarking, existe uma razão pela qual eu deveria preferir uma em vez de outra implementação?

Exemplo completo .

c++
  • 1 respostas
  • 74 Views
Martin Hope
Enlico
Asked: 2024-05-21 16:08:53 +0800 CST

Qual é o bug neste código ou qual é o bug no MSVC? [duplicado]

  • 6
Essa pergunta já tem resposta aqui :
Erro do compilador ao exportar classe (1 resposta)
Fechado há 17 horas .

Aqui está o trecho de código

#include<memory>
#include<unordered_map>

struct
__declspec(dllexport)
Foo {
    std::unordered_map<const int*, std::unique_ptr<int>> foo;
};

Foo foo();

que falha assim :

C:/data/msvc/14.39.33321-Pre/include\list(1299): error C2679: binary '=': no operator found which takes a right-hand operand of type 'const std::pair<const int *const ,std::unique_ptr<int,std::default_delete<int>>>' (or there is no acceptable conversion)
C:/data/msvc/14.39.33321-Pre/include\utility(315): note: could be 'std::pair<_Kty,_Ty> &std::pair<_Kty,_Ty>::operator =(volatile const std::pair<_Kty,_Ty> &)'
        with
        [
            _Kty=const int *,
            _Ty=std::unique_ptr<int,std::default_delete<int>>
        ]
C:/data/msvc/14.39.33321-Pre/include\list(1299): note: 'std::pair<_Kty,_Ty> &std::pair<_Kty,_Ty>::operator =(volatile const std::pair<_Kty,_Ty> &)': cannot convert argument 2 from 'const std::pair<const int *const ,std::unique_ptr<int,std::default_delete<int>>>' to 'volatile const std::pair<_Kty,_Ty> &'
        with
        [
            _Kty=const int *,
            _Ty=std::unique_ptr<int,std::default_delete<int>>
        ]
C:/data/msvc/14.39.33321-Pre/include\list(1299): note: Reason: cannot convert from 'const std::pair<const int *const ,std::unique_ptr<int,std::default_delete<int>>>' to 'volatile const std::pair<_Kty,_Ty>'
        with
        [
            _Kty=const int *,
            _Ty=std::unique_ptr<int,std::default_delete<int>>
        ]

... see linked example for complete error

Vejo que o problema é o fato de std::unique_ptrnão ser copiável, como está implícito, por exemplo, em Reason: cannot convert from 'const std::pair<const int *const ,std::unique_ptr<int,std::default_delete<int>>>' to 'volatile const std::pair<_Kty,_Ty>', mas por que a capacidade de cópia é exigida apenas no Windows e somente com o dllexport?


Na base de código de onde isso foi extraído, __declspec(dllexport)está a expansão de uma macro que se expande para valores diferentes em outras plataformas, por exemplo, __attribute__ ((visibility("default")))no Linux, caso em que o código é compilado perfeitamente.

c++
  • 1 respostas
  • 84 Views
Martin Hope
Enlico
Asked: 2024-04-10 04:03:23 +0800 CST

Posso usar StateT/MaybeT/forever para eliminar a recursão explícita desta ação IO?

  • 8

Eu tenho um programa como este,

start :: [Q] -> R -> IO R
start qs = fix $ \recurse r -> do
  q <- select qs
  (r', exit) <- askQ q r
  (if exit
    then return
    else recurse) r'

que pega uma lista de Qperguntas, uma Report, e retorna uma nova Report, na IOmônada porque selectprecisa escolher uma pergunta aleatoriamente (e também porque askQvai esperar pela entrada do teclado do usuário); no entanto, o usuário não escolheu exitdurante a execução askQ, startirá chamar a si mesmo recursivamente. ( fix $ \recurseé o truque para escrever um lambda recursivo. )

O código acima se parece muito com algumas coisas:

  • a Statemônada , ou, mais apropriadamente, o StateTtransformador de mônada , porque Restá evoluindo durante starta recursão de;
  • o forevercombinador de aplicativos, porque starté recursivo e pode potencialmente ser executado para sempre, se o usuário desejar (ou seja, se ele nunca pedir para sair);
  • o MaybeTtransformador mônada , porque Maybeimplementa MonadPlusque deve poder entrar em curto-circuito forever, com base no que li antes foreverda implementação .

Mas não é possível dizer se alguma ou mais dessas abstrações podem ser usadas para escrever o código acima de uma forma mais idiomática, evitando o mais importante a recursão explícita.

haskell
  • 2 respostas
  • 58 Views
Martin Hope
Enlico
Asked: 2024-04-07 02:00:15 +0800 CST

Para manter o estado em uma função do tipo a -> ReaderT r IO b, minha única opção é colocar um IORef no encerramento? Ou posso de alguma forma usar o StateT?

  • 7

Digamos que eu tenha que implementar uma função

f :: Foo -> ReaderT Bar IO Baz

que tenho que passar para um consumidor (ou seja, vou chamar ) c fonde Foo// são impostos o consumidor da função, e que o consumidor chamará essa função repetidamente com s diferentes.BarBazFoo

Tenho alguma chance de manter algum estado local entre chamadas sucessivas para f?


De alguma forma, já consegui isso através de um IORef, alterando a assinatura def

f :: IORef S -> Foo -> ReaderT Client IO a

e aplicá-lo parcialmente a algum estado que eu inicializei de antemão:

s <- initState :: IO (IORef S)
c $ f s

Dessa forma, o totalmente aplicado fpode alterar o state na IOmônada via atomicModifyIORef'e alguma ufunção pdate:

f s x = do
  liftIO $ atomicModifyIORef' s u
  -- ...

No entanto, a solução acima foi natural para mim porque esse state é realmente um estado mutável global que é modificado não apenas por chamadas para f, mas também por alguma outra parte do programa que é executada simultaneamente com f.

Mas agora preciso de falgum estado privado que não deva ser modificado por mais ninguém. Isso me faz pensar no StateTtransformador, mas não sei se posso aplicá-lo neste caso.


O caso prático em questão é que desejo uma notifyfunção com estado no contexto da implementação de um servidor de notificação. Veja aqui um exemplo de brinquedo da implementação. Neste cenário, Foo -> ReaderT Bar IO Bazé na verdade MethodCall -> ReaderT Client IO Reply( ReaderT Client IO ais DBusR a).

Como você pode ver, o que quer que eu faça com notify, devo acabar passando uma MethodCall -> DBusR Replyfunção para export, cliente essa função será chamada várias vezes e espera-se que retorne sempre, então me parece que a única maneira de manter o estado nela é o seu fechamento, ou seja, tenho que fornecer notifymais um argumento antes MethodCalle aplicá-lo parcialmente ao estado inicial, como expliquei acima. E a única maneira de fazer com que esse estado mude toda vez que a MethodCallfor passado é fazer com que o primeiro argumento adicional seja um estado verdadeiramente mutável, por exemplo, o que IORefmencionei acima.

É isso?

haskell
  • 1 respostas
  • 51 Views
Martin Hope
Enlico
Asked: 2024-02-18 00:13:50 +0800 CST

Por que o Cabal, ao contrário do GHC, não habilita automaticamente o GeneralizedNewtypeDeriving se eu habilitei explicitamente o DerivingStrategies?

  • 7

Pela documentação, estou inclinado a pensar que, se eu habilitar a DerivingStrategiesextensão, não preciso habilitar GeneralizedNewtypeDerivingor DeriveAnyClass, nem qualquer outra extensão listada atualmente antes de §6.6.7.1 , por exemplo DerivingVia.

No entanto, este exemplo de brinquedo

{-# LANGUAGE DerivingStrategies #-}

newtype MyNum = MyNum Int
 deriving stock (Eq, Ord, Show, Read)
 deriving newtype (Num, Enum, Real, Integral)

main :: IO ()
main = print $ MyNum 0

compila muito bem via ghc this-file.hs(GHC 9.4.8), mas não via cabal build(Cabal 3.10.2.1), porque neste último caso, também é necessário que eu adicione

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

Alguma pista do porquê disso?


O foo.cabalarquivo fictício que estou usando é

cabal-version:   3.8
name:            foo
version:         1.0

executable foo
    main-is:          main.hs
    build-depends:    base
haskell
  • 1 respostas
  • 34 Views

Sidebar

Stats

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

    Reformatar números, inserindo separadores em posições fixas

    • 6 respostas
  • Marko Smith

    Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não?

    • 2 respostas
  • Marko Smith

    Problema com extensão desinstalada automaticamente do VScode (tema Material)

    • 2 respostas
  • Marko Smith

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

    • 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

    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
  • Martin Hope
    Fantastic Mr Fox Somente o tipo copiável não é aceito na implementação std::vector do MSVC 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant Encontre o próximo dia da semana usando o cronógrafo 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor O inicializador de membro do construtor pode incluir a inicialização de outro membro? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul O C++20 mudou para permitir a conversão de `type(&)[N]` de matriz de limites conhecidos para `type(&)[]` de matriz de limites desconhecidos? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann Como/por que {2,3,10} e {x,3,10} com x=2 são ordenados de forma diferente? 2025-01-13 23:24:07 +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

Hot tag

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

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help
subwaysurfers
my femboy roommate

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve