<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>@kleedaisuki (English)</title><description>Notes by kleedaisuki on programming, mathematics, research, and ideas.</description><link>https://atelier.moesegfault.dev/en/</link><language>en-US</language><item><title>The Death of Code Review: Toward Agent-Legible Systems</title><link>https://atelier.moesegfault.dev/en/blog/2026-08-24-1-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2026-08-24-1-en/</guid><description>Coding agents are reshaping the cost model of software engineering: code generation is becoming increasingly cheap, while human attention is becoming the new serial bottleneck. Software trustworthiness should not depend on the authority of an author or reviewer, but arise from verifiable and falsifiable system mechanisms. This essay proposes Agent-Legible Systems: systems designed from the outset so that agents can query, experiment with, and verify runtime state, critical invariants, and causal evidence, forming an automated verification loop through type systems, testing, CI, profiling, tracing, and more. Human judgment then moves upward from line-by-line implementation review to domain models, system contracts, and irreversible architectural decisions.</description><pubDate>Mon, 24 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://github.com/kleedaisuki/FOGMOE-telegram-bot&quot;&gt;FOGMOE-telegram-bot&lt;/a&gt; is a summer hobby project of mine, forked from a relatively simple implementation by FOGMOE. After two months of design and refinement—and burning through more Codex quota than I can count—the project now has the basic characteristics of a cloud agent: containerized agent workspaces, the novel fmBPF dynamic plugin system, and reliable operations and deployment tooling.&lt;/p&gt;
&lt;p&gt;The project is implemented natively in Python 3.14 and C++23, targets Linux, and uses PostgreSQL for its data services. According to cloc, the Git-tracked files contain roughly 383,600 nonblank lines of effective code and comments: 244,700 lines of production code and 138,900 lines of test code, split about evenly between Python and C++. This code also comes with quality assurance: the production code contains 9,109 functions, with an average cyclomatic complexity of about 5; in the long tail, 456 functions exceed 15 and 127 exceed 30. The codebase is exceptionally consistent, follows domain-driven design throughout, and uses the type system to constrain and express semantics and business logic. It is a textbook example of top-down implementation following sound design.&lt;/p&gt;
&lt;p&gt;For one person to systematically rewrite a project of roughly 28,000 lines and evolve it into an engineering system of about 380,000 lines within two months would have been impossible just a few years ago. Moreover, even after the pure design and development phase, there are still operations and deployment to handle, as well as product feedback through the Telegram interface—a span far beyond that of a traditional backend engineer.&lt;/p&gt;
&lt;p&gt;Allow me to call software engineering before the widespread adoption of coding agents “traditional software engineering,” because a project like this makes a fundamentally different cost model plainly visible: its scale and efficiency extend far beyond what any engineer&apos;s proficiency in a particular technology stack could cover. Such a vast quantity of code easily overwhelms the economics of human attention. In the past, writing an algorithm and reviewing one could require comparable effort, but an agent can often reproduce an algorithm in mere seconds by going online and consulting best practices. Limited human attention becomes the largest serial component of the entire process. The bottleneck has clearly shifted.&lt;/p&gt;
&lt;p&gt;The most intuitive response is to slow down agents&apos; code output, or to dismiss it all as “AI slop” and return to programming the old-fashioned way. I find this mode of thought and the sentiment behind it immature: it has never concretely demonstrated how much worse “AI slop” is than the work of an experienced senior engineer. Much of engineering taste cannot be measured at all, and one cannot simply declare that spending 99% of the cost for 1% of the performance is necessarily “better.” Before coding agents existed, was the code written by so many backend engineers rushing to ship and meet output targets somehow not slop? Moreover, much of this discourse instinctively invokes AI hallucinations—but why should we assume that a model is sacred and omnipotent in the first place? Does an engineer never make mistakes? And yet why are we able to trust their judgment?&lt;/p&gt;
&lt;p&gt;What, ultimately, makes code worthy of trust?&lt;/p&gt;
&lt;p&gt;I believe code is trustworthy not because its author is trustworthy, but because it can be systematically verified, falsified, and constrained. Code review is merely one form of governance under the old cost model: we trust that this institution can improve code quality and spread knowledge, while engineers&apos; mistakes remain rare enough to recover from. If we return to the proper focus—“If it is wrong, do I have mechanisms good enough to catch it?”—the two elements of such an institution become obvious: first, a threshold for admission; second, mechanisms for fault tolerance.&lt;/p&gt;
&lt;p&gt;Type systems, tests, linting, architectural checks, and CI are all important, but they address risks that we have already modeled explicitly. Real systems are also shaped by data distributions, concurrency, load, dependencies, kernels, networks, scheduling, and failure modes. That is why static analysis, testing, and CI did not replace reviewers even in the past. Engineers possess a higher-level context: they can imagine what their systems look like at runtime and what semantics and protocols must be obeyed.&lt;/p&gt;
&lt;p&gt;Consider today&apos;s coding agents. Reinforcement-learning post-training has raised models&apos; procedural capabilities to a considerable level, even as some loudly proclaim that “scaling has hit a wall” or invoke the “density law.” I do not intend to discuss here what reinforcement-learning post-training actually does within the model sampling process, nor do I want to delve into the gulf between factual and procedural capabilities. What I want to point out is that the achievements of today&apos;s tool-using coding agents rest on two prerequisites: external knowledge can be conveniently obtained through tools, and measurable quantities and feedback mechanisms are available.&lt;/p&gt;
&lt;p&gt;I believe the key to systematic engineering with agents is to let them obtain runtime information invisible in static code and reason from it, instead of relying on knowledge internal to the model for the kind of high-context judgment at which it is not adept. I call systems designed from the outset so that agents can actively query, experiment with, and verify runtime state, critical invariants, and causal evidence &lt;strong&gt;Agent-Legible Systems&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Google SRE became a major school of thought in the cloud-native era because it incorporated operational capability itself into system design, turning reliability from after-the-fact firefighting into a system property that could be designed, measured, budgeted, and automated. I believe the key change in AI-native system design is to incorporate observability into system design. We should not wait until the code has been written to find ways for an agent to understand the system; from the very beginning, the system should be designed around how agents will observe and reason about it.&lt;/p&gt;
&lt;p&gt;We should shift our focus toward infrastructure. For example, we need to provide this kind of capability: instead of an agent reading through the code like an engineer and saying, “Performance is poor here,” the agent can launch a toolchain and workflow, obtain profiling data, and clearly show that “performance is poor here.” Instead of spinning up a host of subagents for review and receiving some number of P0 and P1 findings, an agent can quickly launch a test environment and obtain detailed tracing and crash reports. One of the central values of traditional code review is that reviewers can mentally simulate runtime behavior from experience. We can instead design systems so that agents directly observe the runtime: we provide easy-to-use tools through which they can acquire knowledge, and ensure that the information feeds back into a closed loop.&lt;/p&gt;
&lt;p&gt;We do not need to compress and distill this information, express it better, or visualize it. We need to let the information span the entire space, because agent attention is not expensive. In the past, reconstructing events after the fact required extensive reasoning and tedious tool use before one might experience a flash of insight and notice the problem. Now this process of organizing evidence and discovering patterns can be handed entirely to agents, turning heuristic work into data analysis.&lt;/p&gt;
&lt;p&gt;Accordingly, humans should not—and need not—spend their scarcest attention inspecting thousands of lines of mechanical implementation. They should review domain models, public contracts, critical invariants, migrations, security boundaries, and irreversible architectural decisions. More and more implementation detail can be handed to agents, while human judgment concentrates on what the system ultimately permits to happen and what it must never permit. At the same time, I believe we should practice agile development, poetic programming, and documentation first. “Documentation first” should not mean Big Design Up Front. It should mean prioritizing the preservation of stable facts during collaboration: ADRs, schemas, migrations, typed interfaces, composition roots, and runbooks. This reduces the tacit knowledge for which “only one person knows why” and lets humans and agents work from the same source of truth.&lt;/p&gt;
&lt;p&gt;Looking back at history, the need for communication between heterogeneous systems gave rise to the enterprise service bus; overengineering then gave rise to the idea of microservices; distributed systems, in turn, introduced SRE. This time, agents have profoundly overturned the traditional cost model of software generation. In response, we should design a closed loop in which agents propose hypotheses → manipulate the environment → obtain runtime evidence → falsify hypotheses → modify the system → verify again, thereby creating agent-legible systems. After all, architecture means thinking from the vantage point of a system&apos;s evolutionary lifecycle—its flourishing and decline. This time, we let agents directly feel the system&apos;s breath and pulse, and take part in its evolution.&lt;/p&gt;</content:encoded><category>AI-native</category><category>Agent-Legible Systems</category><category>Software Engineering Paradigm</category><category>Code Review</category></item><item><title>Local Optima Under Closed Conditions</title><link>https://atelier.moesegfault.dev/en/blog/2026-05-03-1-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2026-05-03-1-en/</guid><description>Array-based red-black trees, gaokao finale problems, and PhDs who cannot find jobs are, at bottom, the same thing: closed systems can select for local optima, but the definition of this &apos;optimum&apos; is itself distorted by the closed conditions. The information environment determines the output efficiency of intelligence, and you cannot price what lies outside your cognition.</description><pubDate>Sun, 03 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I have indeed seen a C tutorial on red-black trees written by a Peking University undergraduate, though not a computer science student, but one in bioengineering. Some parts had the beauty of reinvented invention. For example, the so-called &quot;array-based red-black tree&quot; already has a specific name: a cursor-based implementation, as opposed to a pointer-based one. The standard approach is also to abstract allocation and access, rather than hard-code and rewrite the algorithmic logic.&lt;/p&gt;
&lt;p&gt;The standard practice in modern C++ is precisely to use templates to decouple algorithmic logic from the underlying storage and access method. The STL itself is a product of this idea. Containers handle memory management, iterators handle access abstraction, and algorithms interact only with iterators; they do not care at all whether the underlying representation is a pointer-linked list allocated on the heap, cursor indices in an array pool, or offsets inside a memory-mapped file. In the specific case of red-black trees, if you want a cursor-based implementation, the modern approach is to make the &lt;code&gt;node&lt;/code&gt; reference type a template parameter, or to abstract it through a traits or policy class. For instance, a &lt;code&gt;NodeTraits&lt;/code&gt; can define whether &lt;code&gt;reference_type&lt;/code&gt; is a pointer or an array index, and define the concrete implementations of &lt;code&gt;get_left()&lt;/code&gt;, &lt;code&gt;get_right()&lt;/code&gt;, and &lt;code&gt;get_parent()&lt;/code&gt;. Then the rotation, insertion, and deletion logic of the red-black tree can be written entirely against those abstract interfaces, without changing a single line of the algorithm. This is &lt;strong&gt;policy-based design&lt;/strong&gt;, the line of thought Alexandrescu systematically elaborated in &lt;em&gt;Modern C++ Design&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Watching someone derive a known conclusion from zero by relying only on their own intelligence can be intellectually beautiful. The derivation itself has real force of thought. But that beauty also carries a trace of sadness, because at bottom it is a failure of information acquisition efficiency. If he had read Sedgewick&apos;s &lt;em&gt;Algorithms&lt;/em&gt;, or any textbook that covers cursor-based implementations, he could have learned in ten minutes what this thing is called and what the standard approach is, then invested his intelligence in genuinely unsolved problems.&lt;/p&gt;
&lt;p&gt;So later, when I looked at the gaokao, I felt the same way I did when reading that Peking University student&apos;s red-black tree tutorial. Do you say the level is not high? He really did manage to think of it. Do you say the level is high? In terms of actual effect, not necessarily. The gaokao and that student&apos;s red-black tree tutorial are, at the bottom, the same paradox: high-intensity intellectual performance under closed conditions.&lt;/p&gt;
&lt;p&gt;The final problem in gaokao mathematics is a typical example. The problem setter operates inside an extremely constrained knowledge range, namely the high school mathematics syllabus, and designs a problem requiring very high levels of technique. The examinees, too, develop exquisitely refined problem-solving strategies inside this closed space. Do you say these people are not smart? The solutions are indeed clever, and the density of thought is high. Do you say these people are advanced? The techniques they spent three years studying in depth often look, from the perspective of university mathematics, like trivial special cases of known theorems. For example, those suffocating inequality-bounding tricks in gaokao problems are essentially attempts to do what calculus should do while calculus is forbidden. From one angle, this is astonishing: you can still box with one hand tied. But from the perspective of efficiency, why not untie the hand?&lt;/p&gt;
&lt;p&gt;This is the essence of &quot;not very advanced, but able to think of it&quot;: a local optimum developed under artificially manufactured constraints. The information environment determines the output efficiency of intelligence. A closed system can select for the strong under closed conditions, but the definition of &quot;strong&quot; is itself distorted by those closed conditions. The gaokao selects for &quot;the person best at mathematical gymnastics under the premise that advanced tools are forbidden&quot;; Zhihu selects for &quot;the person best at writing within constraints&quot;; that student demonstrates &quot;the person best at independent derivation under information isolation.&quot; Each is a real ability, but each is also being wasted by the constraints. The same intelligence, in an information-rich environment, can stand on the shoulders of giants and push forward; in an information-poor environment, it can only spend enormous effort repaving roads that others have already paved.&lt;/p&gt;
&lt;p&gt;So a person&apos;s level, in fact, depends less on how hard they work than on the information environment they inhabit. For instance, many people&apos;s circles never really come into contact with things like land finance, vertical and horizontal bureaucratic fragmentation, or foreign-exchange facilitation quotas; they also cannot understand what a tax base or liquidity is. Many technical people think the only meaningful difference is the network environment, and this is a form of ignorance: they have no assets to allocate, no enterprise to operate, and you cannot price what lies outside your cognition. So many people can only say &quot;iron rice bowl&quot; and &quot;stability,&quot; while there is a more accurate term they do not know how to use: endorsement by state credit.&lt;/p&gt;</content:encoded><category>Information Environment</category><category>Gaokao</category><category>Academia and Industry</category><category>C++</category></item><item><title>AI as a New Infrastructure for Knowledge Transmission</title><link>https://atelier.moesegfault.dev/en/blog/2026-05-01-1-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2026-05-01-1-en/</guid><description>The rise in humanity&apos;s average capability comes less from individuals studying longer than from the continuous upgrading of how knowledge is diffused, compressed, and invoked.</description><pubDate>Fri, 01 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Because most of the time we are dealing with normal science, there are in fact not that many genuine points of innovation. Most work is, at bottom, engineered repetition, tuning, and pattern matching. The rise in humanity&apos;s average level does not come from people across history suddenly having more time to study; it comes from knowledge becoming easier and easier to diffuse. When Newton and Leibniz invented calculus in the seventeenth century, it stood at the absolute frontier of human intellectual activity. Today, a high school student can grasp its basic framework in a few months. The community has in effect formed a division-of-labor mechanism: it prevents later generations from repeatedly starting from zero, and it gradually turns &quot;reinventing the wheel&quot; into something inefficient and faintly suspicious.&lt;/p&gt;
&lt;p&gt;In computer science, the overwhelming majority of papers are also doing normal science. After the emergence of the Transformer, thousands of papers have essentially been doing this: swapping datasets, adding a module, changing the loss function. These are engineering evolutions inside the Transformer paradigm, not ruptures at the level of fundamental concepts. The nodes that truly deserve to be called innovations may be only a few: the attention mechanism itself, the discovery of scaling laws, RLHF as a formed alignment strategy, and the theoretical framework of diffusion models. Much of the rest is closer to exploitation than exploration.&lt;/p&gt;
&lt;p&gt;The main mechanism here is the continuous iteration of technologies for encoding, compressing, and transmitting knowledge. Writing, the printing press, academic journals, the internet, and now AI: each has been an upgrade of the infrastructure of transmission. In &lt;em&gt;The Gifts of Athena&lt;/em&gt; (2002), Joel Mokyr distinguishes between two kinds of knowledge: propositional knowledge (&quot;what is,&quot; or Ω knowledge) and prescriptive knowledge (&quot;how to,&quot; or λ knowledge). His core argument is that the Industrial Revolution happened not because human beings suddenly became smarter, but because the mapping between these two kinds of knowledge became more efficient: people could more quickly convert &quot;knowing the principle of X&quot; into &quot;knowing how to use X to do things.&quot;&lt;/p&gt;
&lt;p&gt;If normal science is repeated practice over specific patterns, if the bottleneck of human progress lies more in transmission than in discovery, and if one function of the community is to avoid meaningless repetition through division of labor, then AI&apos;s impact on academia is not merely that &quot;papers can be written faster.&quot; The sharper judgment is this: AI may be making large portions of the human labor invested in normal science unnecessary. If 90% of academic output consists of incremental filling-in within existing paradigms, and AI can already handle a substantial share of that filling-in, then what exactly is the rationale for maintaining a global academic labor force of several million people to perform this task?&lt;/p&gt;
&lt;p&gt;In the past, what was the transmission mechanism for knowledge such as &quot;how to write a paper&quot;? It was apprenticeship. You worked under an advisor, and the advisor taught you by hand: how to design a baseline so the experiment looks fair, how to write related work without offending reviewers, how to calibrate the tone of a rebuttal, and how the first sentence of an abstract should hook an editor. These things are not fully written in any textbook. They are procedural knowledge, embedded in a specific structure of social relations and passed on orally through apprenticeship. Whether you can learn them therefore depends, in essence, on who your advisor is. What a student in a top lab absorbs almost by osmosis, a student at an ordinary institution may still not know after finishing a PhD. The channels through which knowledge is transmitted are bound to the hierarchy of academic power. The concept of tacit knowledge, developed by Michael Polanyi in &lt;em&gt;Personal Knowledge&lt;/em&gt; (1958), describes precisely this layer; his later famous formulation, &quot;we can know more than we can tell,&quot; also points to the fact that such knowledge cannot be fully made explicit, cannot be sufficiently carried by textbooks, and can only circulate within communities of practice.&lt;/p&gt;
&lt;p&gt;What has AI done? It has lowered the threshold for acquiring this layer of tacit knowledge from &quot;you first have to spend years as an apprentice inside a guild&quot; to &quot;you have to know how to ask questions.&quot; &quot;Let AI look at the paper; it basically functions like peer brainstorming&quot; was almost unimaginable two years ago. If a doctoral student wanted high-quality peer feedback, they either waited months for formal peer review or found a peer in the same direction who was willing to spend time reading the paper carefully. Now, you can obtain a reasonably capable intellectual sparring partner at any time. And notice: this is not merely an efficiency gain. It is a transfer of power. In the past, perhaps only a few thousand doctoral students in China&apos;s top laboratories could access feedback of this quality. Now, anyone with access to Claude or GPT, and with enough skill to ask good questions, can obtain something similar.&lt;/p&gt;
&lt;p&gt;In the short term, academia will not fundamentally change because of this, since academic power is not built entirely on the monopoly of knowledge. It is built more deeply on credential certification and network access. Being able to write a paper does not mean you can get it published, because the bottleneck of publication is often not only paper quality, but also whether reviewers know your advisor and whether your institution possesses enough reputational capital. In the long run, however, if AI continues to lower the threshold of knowledge production, then the intermediaries that maintain their status purely through information asymmetry, such as those who do little research themselves but allocate resources through academic administrative power, will face an increasingly severe legitimacy crisis. This change, however, will be slow: the inertia of the guild is far more stubborn than the speed of technological iteration.&lt;/p&gt;</content:encoded><category>AI-Native</category><category>Knowledge Transmission</category><category>Academic Production</category></item><item><title>After Diligence Was Invented as an Ability</title><link>https://atelier.moesegfault.dev/en/blog/2026-02-01-1-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2026-02-01-1-en/</guid><description>To call exam-oriented education fair is a fundamental misrecognition: it merely renames the absence of choice as the superiority of the only available choice.</description><pubDate>Sun, 01 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I think a mistaken value judgment circulates almost everywhere in society: diligence is treated as an ability.&lt;/p&gt;
&lt;p&gt;This is deeply connected to exam-oriented education. The examination system has one central feature: it compresses multidimensional human capacities into a single measurable index. Once the evaluative standard becomes highly standardized, one consequence follows immediately: the ceiling of methodology is low, while the ceiling of time investment is almost infinite. In other words, once the question of &quot;how to study&quot; has been fixed as doing drills, memorizing, and repeating, the only operational variable left is &quot;how long to study.&quot; Diligence is then elevated above other capacities and becomes, within this particular game, the form of input most capable of producing marginal returns.&lt;/p&gt;
&lt;p&gt;I find it quite superficial to understand exam-oriented education as &quot;a relatively fair screening mechanism under conditions of extreme resource scarcity.&quot; This is a depoliticized explanation: it narrates institutional choice as something natural and inevitable. Such analysis carries an implicit tendency, namely, to treat institutions as passive responses to objective constraints rather than as active operations of power. Placed back into reality, this is clearly lopsided.&lt;/p&gt;
&lt;p&gt;The fundamental problem, in my view, is not extreme resource scarcity, but administrative domination over education and a highly centralized institutional design. China&apos;s educational resources have grown substantially over the past two or three decades: the number of schools, the quality of teachers, and basic infrastructure have all improved. Yet the intensity of examination competition has not decreased; it has become even more brutal. If resource scarcity were truly the root cause, then an increase in resources should have alleviated the problem. What actually happened is that additional resources were absorbed into the same competitive logic, becoming more refined drilling and an ever earlier starting line.&lt;/p&gt;
&lt;p&gt;At its core, this is the state&apos;s monopoly over ideology. Unified textbooks, unified exam syllabi, unified grading standards, and a unified route of educational advancement make plural standards of evaluation difficult to sustain. Even if a particular school or teacher wants to experiment with a different educational philosophy, that attempt will be systematically filtered out.&lt;/p&gt;
&lt;p&gt;Only from this perspective can we explain several key functions of Chinese school education:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Population screening and sorting: social stratification is completed under a highly unified standard, while those who are sorted downward are made to &quot;accept their fate,&quot; because failure is explained as &quot;you simply did not work hard enough.&quot;&lt;/li&gt;
&lt;li&gt;Discipline and training in obedience: the core capacity trained by exam-oriented education may not be &quot;knowledge,&quot; but &quot;the ability to execute instructions under conditions where the meaning is unclear.&quot;&lt;/li&gt;
&lt;li&gt;The dissolution of locality and plurality: unified educational content is a tool for ideological integration.&lt;/li&gt;
&lt;li&gt;The deferral of social contradiction: young people are made to exhaust their energy in endless competition rather than question the system itself.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To call exam-oriented education fair is a fundamental misrecognition; I think this comes largely from a constricted worldview. Fairness should mean equality of opportunity within competition, not the disabling of other options so that most people are forced to choose the examination track. This also explains what feels so treacherous about exam-oriented education: elites possess the right to exit. They can study abroad; they can inherit. So perhaps calling it fair is also a defensive mechanism against trauma. It merely renames the absence of choice as the superiority of the only available choice.&lt;/p&gt;</content:encoded><category>Education Critique</category><category>Institutional Analysis</category><category>Musings</category></item><item><title>Xianxia, Light Novels, and Cultural Models of Competition</title><link>https://atelier.moesegfault.dev/en/blog/2025-11-29-1-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2025-11-29-1-en/</guid><description>The fundamental fracture between premodernity and modernity lies in the optimization target: no longer whether I am omnipotent and miss nothing, but what specific demand I can satisfy within the supply chain.</description><pubDate>Sat, 29 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The world is, of course, full of competition. Yet there are profound differences in how competition itself is understood. Generally speaking, when one frames a problem, different models produce different definitions of demand and optimization targets, which in turn reshape the subsequent choice of path and mode of optimization. Competition can likewise be modeled through two sharply divergent logics. For convenience, I will call them stock thinking and growth thinking.&lt;/p&gt;
&lt;p&gt;The contrast between Chinese xianxia fiction and Japanese light novels makes this difference easy to perceive. Japanese light novels are especially fond of farming stories and merchant stories, such as &lt;em&gt;Spice and Wolf&lt;/em&gt; and &lt;em&gt;Ascendance of a Bookworm&lt;/em&gt;. Their protagonists usually do not acquire resources through plunder; instead, they accumulate wealth by introducing new technologies: making paper in another world, producing soap, improving crops, and so on. Behind this lies a relatively stable consensus in developed societies: wealth can be created, rather than merely seized from the hands of others.&lt;/p&gt;
&lt;p&gt;Broadly speaking, Chinese popular fiction over the past period reflects a society of rapid growth and violent class mobility. People believe that &quot;kings, nobles, generals, and ministers are not born as such,&quot; while also fearing, with equal intensity, that falling behind means being beaten. Its system design is therefore often extremely aggressive and extremely cruel. Japanese works, by contrast, reflect a mature, solidified, even nearly stagnant society. People are already accustomed to the idea that everyone has a place, that is, a division of labor. They are less inclined to fantasize constantly about becoming omniscient and omnipotent gods; they would rather find a comfortable position within a system that still functions reasonably well: opening a cafe, perhaps, or becoming a mid-level adventurer.&lt;/p&gt;
&lt;p&gt;What is even more interesting is that the economy of cultivation fiction is, in essence, a worship of hard currency. Spirit stones are the gold standard, and in fact more primitive than the gold standard: they are both a general equivalent and a consumable. Within this worldview, institutional imaginaries such as lending, futures, and insurance are almost entirely absent. Since there is no financial leverage, the main mode of resource circulation is reduced to a single word: seize. Murdering someone and taking their treasure therefore becomes the most efficient form of &quot;asset restructuring.&quot; This is precisely the smallholder economic mentality produced by a deflationary spiral: total resources are limited; if I do not take yours, I will starve. The great powers of xianxia can live for tens of thousands of years, yet they still seem incapable of understanding compound interest, investment, or credit. They merely seal spirit stones away layer upon layer in the depths of their caves.&lt;/p&gt;
&lt;p&gt;Why do Chinese authors so rarely write a &quot;Wall Street of the cultivation world&quot; or a &quot;social security bureau of the cultivation world&quot;? Because in the database of the Chinese collective unconscious, there are roughly only two mature architectural blueprints:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The Qin-Han commandery-county system and bureaucracy&lt;/li&gt;
&lt;li&gt;The clan system of rural society&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Civil society, contractual spirit, and modern banking are things that have only been hastily patched in over the past few decades.&lt;/p&gt;
&lt;p&gt;When authors construct fantasy worlds, they instinctively roll back to the old kernel they know best, the one that feels most &quot;authentic.&quot; Even with an iPhone in hand, the logic running in their heads remains that of the imperial court, the martial world, and the county office. This exposes a kind of cognitive poverty: it is difficult to imagine a society that possesses both supernatural power and modern civilizational institutions. In this sense, China&apos;s modernization remains, to a large extent, a modernization of implements. It has by no means fully reached the modernization of thought structures and social institutions.&lt;/p&gt;
&lt;p&gt;Different understandings of competition naturally produce radically different modes of action. If we keep thinking only about how to seize opportunities from others, we will keep reenacting the primitive omnipotence fantasy of the xianxia protagonist: forever anxious about whether we lag behind others on some metric, forever terrified of even the slightest so-called &quot;falling behind.&quot; Yet modern industrial society is, at its root, anti-omnipotence. Each person and each enterprise should do its own work in a highly cohesive and loosely coupled way; abundant middleware, layers of abstraction, and professional specialization are the real face of the modern supply chain. The right question is not &quot;how many things can I do,&quot; but &quot;where am I positioned in the supply chain,&quot; and then how to push the depth of that one thing to its limit until it becomes a moat.&lt;/p&gt;
&lt;p&gt;This is why the competitive anxiety of many Chinese people, and of Chinese-style parents in particular, is fundamentally meaningless. They know only that one should outperform others on some metric, yet rarely think seriously about one&apos;s own ecological niche or one&apos;s own track. Their optimization target is always &quot;how omnipotent am I,&quot; rather than &quot;what specific demand can I satisfy.&quot; This is the fundamental fracture between premodernity and modernity, and it is indeed the psychology of an overgrown infant that cannot relinquish the fantasy of omnipotence.&lt;/p&gt;</content:encoded><category>Popular Culture</category><category>Modernity</category><category>Competition</category><category>Musings</category></item><item><title>C++ Fundamentals: Hardware Brutalism and Zero-Cost Abstraction</title><link>https://atelier.moesegfault.dev/en/blog/2025-11-29-2-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2025-11-29-2-en/</guid><description>From std::fma to allocator_traits, SFINAE, PMR, and Concepts: the sharpness of C++ lies in how it forces hardware facts and the type system into the same room.</description><pubDate>Sat, 29 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;C++ fundamentals time. Today, let us feel again the core temperament of C++: hardware brutalism, and zero-cost abstraction.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;There is a function dedicated to floating-point multiply-add: &lt;code&gt;std::fma&lt;/code&gt;, whose name comes from Fused Multiply-Add. You give it &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;, and &lt;code&gt;z&lt;/code&gt;, and it returns &lt;code&gt;x * y + z&lt;/code&gt;. Someone may ask: &quot;How is that different from just writing &lt;code&gt;x * y + z&lt;/code&gt;?&quot; The key is precisely that word: &lt;strong&gt;Fused&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The ordinary expression &lt;code&gt;x * y + z&lt;/code&gt; usually proceeds in two steps. First it computes &lt;code&gt;temp = x * y&lt;/code&gt;. During this process, the result is rounded to the precision representable by the floating-point format, such as the 53 significant bits of &lt;code&gt;double&lt;/code&gt;. Precision has already been lost once. Then it computes &lt;code&gt;result = temp + z&lt;/code&gt;, where another rounding occurs. In total, there are two rounding errors.&lt;/p&gt;
&lt;p&gt;By contrast, under IEEE 754, &lt;code&gt;std::fma(x, y, z)&lt;/code&gt; must compute the exact value of &lt;code&gt;x * y + z&lt;/code&gt; as if it had infinite intermediate precision, and only then perform a single rounding when storing the result back into the floating-point format. This means &lt;code&gt;std::fma&lt;/code&gt; is usually more accurate than ordinary multiply-add. It is especially valuable when &lt;code&gt;x * y&lt;/code&gt; and &lt;code&gt;z&lt;/code&gt; are close in magnitude but opposite in sign, producing catastrophic cancellation; &lt;code&gt;std::fma&lt;/code&gt; can preserve more significant digits.&lt;/p&gt;
&lt;p&gt;Modern CPUs, such as Intel architectures since Haswell and ARM Cortex-A series cores, usually support FMA instructions directly at the ISA level, such as x86 FMA3 or the historical FMA4 instruction set. &lt;code&gt;std::fma&lt;/code&gt; is often compiled into a single assembly instruction, for example &lt;code&gt;vfmadd213sd&lt;/code&gt;. That means it is not only more accurate, but also extremely fast, often taking only 4-5 clock cycles while offering high throughput.&lt;/p&gt;
&lt;p&gt;But if the hardware does not support it, the compiler may call a software library to emulate infinite intermediate precision. At that point it can become very slow. The standard defines three optional macros, &lt;code&gt;FP_FAST_FMA&lt;/code&gt;, &lt;code&gt;FP_FAST_FMAF&lt;/code&gt;, and &lt;code&gt;FP_FAST_FMAL&lt;/code&gt;, to report the ground truth: whether FMA is actually &quot;fast&quot; on this machine.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Imagine writing a &lt;code&gt;std::list&amp;#x3C;int&gt;&lt;/code&gt; and passing in &lt;code&gt;std::allocator&amp;#x3C;int&gt;&lt;/code&gt; as the allocator. Internally, however, a linked list does not store lonely &lt;code&gt;int&lt;/code&gt; objects directly; it stores nodes, say &lt;code&gt;Node&amp;#x3C;int&gt;&lt;/code&gt;. The allocator only knows how to allocate memory of &lt;code&gt;int&lt;/code&gt; size, so where do the &lt;code&gt;next&lt;/code&gt; / &lt;code&gt;prev&lt;/code&gt; pointer fields inside &lt;code&gt;Node&lt;/code&gt; go? This is where allocator rebinding is needed. In the early model, it was implemented through a &lt;code&gt;rebind&lt;/code&gt; struct.&lt;/p&gt;
&lt;p&gt;Before C++11, for example in C++98, the standard required every allocator to manually provide a &lt;code&gt;rebind&lt;/code&gt; struct. In C++11 and later, &lt;code&gt;std::allocator_traits&lt;/code&gt; uses SFINAE techniques to detect whether the user has written &lt;code&gt;rebind&lt;/code&gt;: if so, it uses the user-defined version; if not, it automatically substitutes the template parameter and generates the corresponding allocator type.&lt;/p&gt;
&lt;p&gt;What is SFINAE? It stands for Substitution Failure Is Not An Error: if invalid code appears while substituting template parameters, such as accessing a type that does not exist, the compiler does not immediately issue an error. Instead, it treats that overload as non-viable and continues looking for another candidate. One caveat matters: SFINAE only protects substitution failures in the immediate context, including return types, function parameter types, and default template parameters. It does not protect code inside the function body.&lt;/p&gt;
&lt;p&gt;The first-generation and most classical SFINAE tool is &lt;code&gt;std::enable_if&lt;/code&gt;. Its mechanism relies on partial specialization: if the condition is true, it has a &lt;code&gt;type&lt;/code&gt; member; if the condition is false, it has no &lt;code&gt;type&lt;/code&gt; member, thereby triggering SFINAE and making the function disappear from the candidate set. Here is pseudocode Gemini generated for me:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;#include &amp;#x3C;type_traits&gt;
#include &amp;#x3C;iostream&gt;

// Version 1: exists only when T is a floating-point type
template &amp;#x3C;typename T&gt;
typename std::enable_if&amp;#x3C;std::is_floating_point&amp;#x3C;T&gt;::value, void&gt;::type
process(T t) {
    std::cout &amp;#x3C;&amp;#x3C; &quot;Processing floating point: &quot; &amp;#x3C;&amp;#x3C; t &amp;#x3C;&amp;#x3C; std::endl;
}

// Version 2: exists only when T is an integer type
template &amp;#x3C;typename T&gt;
typename std::enable_if&amp;#x3C;std::is_integral&amp;#x3C;T&gt;::value, void&gt;::type
process(T t) {
    std::cout &amp;#x3C;&amp;#x3C; &quot;Processing integer: &quot; &amp;#x3C;&amp;#x3C; t &amp;#x3C;&amp;#x3C; std::endl;
}

int main() {
    process(3.14); // Matches version 1; version 2 is discarded by SFINAE
    process(42);   // Matches version 2; version 1 is discarded by SFINAE
    // process(&quot;Hello&quot;); // Both fail; only now is it a real Compile Error
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;typename&lt;/code&gt; in there is purely a C++ syntax issue. Before template instantiation, the compiler by default treats whatever follows a scope-resolution operator as a variable or value. So why is &lt;code&gt;typename&lt;/code&gt; sometimes necessary and sometimes absent? The core issue is dependent names: whether the compiler can eliminate the ambiguity at the current stage.&lt;/p&gt;
&lt;p&gt;For example, &lt;code&gt;std::vector&amp;#x3C;int&gt;::iterator&lt;/code&gt; is not a dependent name. Because &lt;code&gt;std::vector&amp;#x3C;int&gt;&lt;/code&gt; is fully determined, the compiler can look it up and know that &lt;code&gt;iterator&lt;/code&gt; is a type, so &lt;code&gt;typename&lt;/code&gt; is unnecessary. But &lt;code&gt;T::iterator&lt;/code&gt; is a dependent name, because the meaning of &lt;code&gt;iterator&lt;/code&gt; depends on what &lt;code&gt;T&lt;/code&gt; actually is. For dependent names, the compiler assumes a value by default, so &lt;code&gt;typename&lt;/code&gt; must be used to explicitly mark it as a type. There is another similar syntactic trap, called &lt;code&gt;.template&lt;/code&gt;, or &lt;code&gt;-&gt;template&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;template &amp;#x3C;typename T&gt;
void call_foo(T&amp;#x26; t) {
    // Wrong! The compiler may parse this as: (t.foo &amp;#x3C; 3) &gt; (5)
    // t.foo&amp;#x3C;3&gt;(5);

    // Correct! Tell the compiler that &amp;#x3C; begins a template argument list
    t.template foo&amp;#x3C;3&gt;(5);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By C++17, we obtained a more elegant technique specifically for detecting whether a class has a certain member.&lt;/p&gt;
&lt;p&gt;The role of &lt;code&gt;std::void_t&amp;#x3C;...&gt;&lt;/code&gt; is this: no matter what types you put inside it, as long as they are valid types, the result is &lt;code&gt;void&lt;/code&gt;; if any expression is invalid, SFINAE is triggered. Gemini example time again, this time detecting whether a class has a &lt;code&gt;reserve()&lt;/code&gt; function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;#include &amp;#x3C;type_traits&gt;
#include &amp;#x3C;vector&gt;
#include &amp;#x3C;iostream&gt;

// Primary template: assume there is no reserve
template &amp;#x3C;typename T, typename = void&gt;
struct has_reserve : std::false_type {};

// Specialized version: use SFINAE to probe
// If T.reserve(size_t) is valid, std::void_t&amp;#x3C;&gt; becomes void and this specialization matches.
// If it is invalid, this line is invalid; SFINAE removes the specialization and falls back to the primary template.
template &amp;#x3C;typename T&gt;
struct has_reserve&amp;#x3C;T, std::void_t&amp;#x3C;decltype(std::declval&amp;#x3C;T&gt;().reserve(1U))&gt;&gt;
    : std::true_type {};

int main() {
    std::cout &amp;#x3C;&amp;#x3C; has_reserve&amp;#x3C;std::vector&amp;#x3C;int&gt;&gt;::value &amp;#x3C;&amp;#x3C; std::endl; // 1 (True)
    std::cout &amp;#x3C;&amp;#x3C; has_reserve&amp;#x3C;int&gt;::value &amp;#x3C;&amp;#x3C; std::endl;              // 0 (False)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;std::declval&amp;#x3C;T&gt;()&lt;/code&gt; is a fascinating little thing:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;template &amp;#x3C;typename T&gt;
typename std::add_rvalue_reference&amp;#x3C;T&gt;::type declval() noexcept;
// That is, it returns T&amp;#x26;&amp;#x26;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After C++11 introduced &lt;code&gt;decltype&lt;/code&gt;, we often need to ask the compiler: &quot;If I had two variables &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;, and I added them as &lt;code&gt;x + y&lt;/code&gt;, what would the resulting type be?&quot; If we have actual instances, this is easy. But in template metaprogramming, we usually have only the type &lt;code&gt;T&lt;/code&gt;, not an instance. At that point, writing &lt;code&gt;decltype(std::declval&amp;#x3C;T&gt;().foo())&lt;/code&gt; makes the compiler perform semantic analysis on the expression. Because this occurs in a type-parameter position, namely the immediate context, a deduction failure hits the SFINAE rule and removes that option from the candidate set. However, &lt;code&gt;std::declval&lt;/code&gt; may only be used in unevaluated contexts.&lt;/p&gt;
&lt;p&gt;Fortunately, the later introduction of polymorphic memory resources (PMR, Polymorphic Memory Resources) and Concepts ended many pages of obscure template scripture.&lt;/p&gt;
&lt;p&gt;Before PMR, the allocator was part of the container type. &lt;code&gt;std::vector&amp;#x3C;int, AllocA&gt;&lt;/code&gt; and &lt;code&gt;std::vector&amp;#x3C;int, AllocB&gt;&lt;/code&gt; were two completely different types. This meant you could not pass them to the same ordinary function unless you also made that function a template; the result was severe code bloat and extremely inflexible interfaces. &lt;code&gt;std::pmr&lt;/code&gt; uses virtual functions and type erasure to hide the concrete memory-allocation strategy at runtime. Now &lt;code&gt;std::pmr::vector&amp;#x3C;int&gt;&lt;/code&gt; is a single type. Whether the underlying resource is &lt;code&gt;new_delete_resource&lt;/code&gt; or a hand-rolled &lt;code&gt;monotonic_buffer_resource&lt;/code&gt;, the container type remains unchanged. In essence, this trades the cost of virtual function calls for smaller code size and simpler interfaces. It is a very typical engineering compromise.&lt;/p&gt;
&lt;p&gt;In the past, using &lt;code&gt;enable_if&lt;/code&gt; together with SFINAE produced code filled with angle brackets. Once an error occurred, the compiler would emit thousands of lines of &quot;template instantiation failed&quot; stack traces, making it almost impossible to see which condition was missing. Concepts, meaning compile-time constraints, let us describe type requirements in something close to natural language.&lt;/p&gt;
&lt;p&gt;The dark age:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;template &amp;#x3C;typename T,
          typename = typename std::enable_if&amp;#x3C;std::is_integral&amp;#x3C;T&gt;::value&gt;::type&gt;
void foo(T t) { /* ... */ }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The bright age:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;void foo(std::integral auto t) { /* ... */ }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Overall, PMR ended the type fragmentation caused by Allocator. It moved complexity from the compile-time type system into runtime object state, making code feel closer to traditional OOP. Concepts ended the obscure syntax of SFINAE. They turned implicit substitution failure into explicit constraint checking, reducing template programming from black magic into ordinary engineering. And with that, the almost dangerous sharpness of C++ finally gained a handle that human beings can actually grip.&lt;/p&gt;</content:encoded><category>Modern C++</category><category>Floating Point</category><category>Template Metaprogramming</category></item><item><title>A Heresy About AI</title><link>https://atelier.moesegfault.dev/en/blog/2025-11-20-1-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2025-11-20-1-en/</guid><description>Most schools, companies, and individuals have not really understood AI; what they understand is the anxiety, slogans, and imitative posture around it.</description><pubDate>Thu, 20 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I want to state a small heresy.&lt;/p&gt;
&lt;p&gt;Most schools, companies, and individuals have not really understood AI. More formally, their organizational inertia is too heavy, and they have not yet built AI-native standards, workflows, or modes of evaluation. More bluntly, they are simply following the crowd: everyone says they need AI, so once the FOMO kicks in, they too announce that they must have this thing.&lt;/p&gt;
&lt;p&gt;This cognitive dissonance is obvious enough when a team claims it wants to hire &quot;people who know how to use AI,&quot; while banning AI in interviews and even moralizing the matter into a question of integrity. In general, hiring is supposed to find people who can solve problems. Management, too, should first be management by outcomes: staying compliant, following the team&apos;s workflow, avoiding production incidents, and delivering reliably. As for how exactly the problem gets solved, that is called agency. At bottom, it is a matter of tool choice: Google or ChatGPT.&lt;/p&gt;
&lt;p&gt;Yet in practice, they leave genuinely scarce project experience and work experience unexplored, and instead keep grinding through standardized questions that AI can annihilate in seconds, as if they were trying to compete with the tool itself on efficiency. Then, with charming seriousness, they add that they also want to &quot;empower&quot; things with AI. Is this not absurd?&lt;/p&gt;
&lt;p&gt;Many people still understand AI only at the level of a &quot;code generator,&quot; without grasping how it is changing the organization of knowledge and the use of human attention. As for the familiar claim that one &quot;does not feel comfortable relying on it,&quot; that is often just instinctive fear before an unfamiliar mode of collaboration. Worse still, some have begun using AI to screen resumes, which is almost a textbook misuse; Amazon already ran that experiment on everyone&apos;s behalf. So in many vertical scenarios, the respectable term is exploration. The blunt term is AI theater.&lt;/p&gt;</content:encoded><category>AI</category><category>AI-native</category><category>Musings</category></item><item><title>Refusing the Problem Set: From Standard Answers to Risk Consciousness</title><link>https://atelier.moesegfault.dev/en/blog/2025-10-20-1-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2025-10-20-1-en/</guid><description>The deepest side effect of exam training is not that it asks people to solve problems, but that it trains the world into a set of judgeable standard answers: rewarding the correct, punishing the wrong, and gradually making people fear error, deviation, and risk itself.</description><pubDate>Mon, 20 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I have never liked doing problem sets. More precisely, I have never liked exam-oriented training. This is not because I come from the kind of resource background where one can simply afford not to do problems, nor do I think there is anything shameful about taking part in exams. As I once put it to a group of friends: if one cannot participate in the U.S. stock market and therefore chooses domestic wealth management products, that is rational decision-making; if one clearly can participate in the U.S. stock market and still chooses domestic wealth management products, that is a matter of low cognition. Of course, this does not include those high-level players technically capable of navigating the A-share market. The point of the analogy is simply this: very often, the problem is not that people are incapable, but that there is no sufficiently good pool available for them to choose from. Different rationalities are therefore generated under different constraints.&lt;/p&gt;
&lt;p&gt;The deepest side effect of exam training is that it injects into people an extremely bad habit: fear of making mistakes, and fear of deviating from some predetermined standard. A test presupposes an answer, and it also presupposes a judge. It rewards the &quot;correct&quot; and devalues the &quot;wrong.&quot; In an environment that negates error over a long period of time, people can easily come to understand error itself as a failure of character or ability, rather than as a necessary cost of exploration.&lt;/p&gt;
&lt;p&gt;Yet in reality, without trial and error, it is very difficult for a person to truly understand what they want. The fields of knowledge in this world are so vast that ignorance is the normal condition for everyone. You may become an expert in certain areas, but you must also acknowledge your insufficiency in others. A sense of direction matters far more than &quot;how much work has been done&quot;; one cannot expect execution ability to conceal a poverty of decision-making ability.&lt;/p&gt;
&lt;p&gt;Reality is always full of ambiguous zones, and risk and return are forever two sides of the same coin. Good decisions do not automatically emerge from the fluency of execution; they are gradually formed in the turbulence, pressure, and trade-offs of reality. If a person develops learned helplessness toward risk and error, then the possibility of iteration is naturally cut off. Even when we speak of execution ability, many people do not act from self-drive or a sense of achievement, but are undertaking a kind of ascetic discipline. As I see it, busyness can never finally conceal the emptiness of meaning. Many people work hard at &quot;doing problems&quot; not because they are curious about knowledge, or because they take pleasure in creation, but simply because they have become accustomed to avoiding punishment as their governing principle of action.&lt;/p&gt;</content:encoded><category>Self-Growth</category><category>Anti-Exam Culture</category><category>Risk Consciousness</category></item><item><title>Composition Is a Worldview</title><link>https://atelier.moesegfault.dev/en/blog/2025-10-09-1-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2025-10-09-1-en/</guid><description>Choices are hard to understand across different maps of the world; what moves us is not the amount of suffering endured, but the capacity to keep choosing love, goodness, and justice in the face of it.</description><pubDate>Thu, 09 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Composition is a worldview.&lt;/p&gt;
&lt;p&gt;Sometimes I find other people&apos;s choices hard to understand. But often the problem is not that a single judgment has gone astray; it is that the entire worldview behind it no longer shares the same coordinate system. Everyone is effectively making decisions while holding only one corner of the whole map. So right or wrong, there will always be gains and losses. Some people simply see more of the terrain, and therefore hold heavier chips in their hands.&lt;/p&gt;
&lt;p&gt;As someone trained in engineering, I have to know and admit this: the world is not determined by technology alone, still less does it revolve only around my own skills. I may understand a particular domain better, and I may make a living from it, but that does not mean other forms of knowledge cannot help me live more deeply, more steadily, and more freely.&lt;/p&gt;
&lt;p&gt;I cannot have professional competence alone while keeping only a thin, superficial image of society, politics, and economics. Skill is only one dimension of a person. The barrel that can truly hold water is a rich and layered structure of knowledge; the capacity and disposition for continuous learning are the source that keeps it evergreen.&lt;/p&gt;
&lt;p&gt;As for those who choose to dance on what I take to be a sinking ship, I do not think there is much to reproach. But if they have thought it through, they are warriors; if they have not, they are almost martyrs. I have always believed that what moves us about a person is never how much suffering they have encountered, but the resilience and courage they still show when facing it.&lt;/p&gt;
&lt;p&gt;That is why, in works of art and literature, even when sacrifice and tragedy appear in various forms, some people inspire reverence and astonishment because they act while knowing the impossibility before them. Others leave only regret and elegy, because before they have understood the road that brought them there, they have already stopped, obscurely and irreversibly.&lt;/p&gt;
&lt;p&gt;Similarly, the radiance of morality does not lie in obedience to discipline, but in the active choice of love, goodness, and justice under conditions of freedom. To react reflexively because of chastity doctrines absorbed since childhood is the posture of a Little Pink. To have seen the darkest and deepest side of things, and still choose to act, is to be a patriot.&lt;/p&gt;
&lt;p&gt;Likewise, a choice may be a form of courage in facing reality; it may also be nothing more than a low waterline of cognition, an almost total blankness in the relevant field of knowledge. There is no ready-made right or wrong here. Everyone merely pushes down their chips and entrusts their wish to time. Merits and faults across the ages will be judged by those who come after; one need only do one&apos;s own work well.&lt;/p&gt;</content:encoded><category>Notes</category><category>Worldview</category><category>Ethics</category></item><item><title>Where Exactly Is the Boundary of Runtime Computation?</title><link>https://atelier.moesegfault.dev/en/blog/2025-10-06-1-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2025-10-06-1-en/</guid><description>When an operand does not originate from IO, runtime is often an engineering trade-off rather than an ontological fate.</description><pubDate>Mon, 06 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;What, exactly, must a computation be in order to count as runtime?&lt;/p&gt;
&lt;p&gt;We have long been able to regard a program as a mapping: it is composed of a sequence of ordered operators. If a computation must occur at runtime, then the operands of that computation must be obtained by initiating IO. Apart from that, strictly speaking, it can all be completed at compile time; the remaining question is one of engineering trade-offs.&lt;/p&gt;
&lt;p&gt;Since C++98, the template system has been Turing-complete, and this opened the path for compile-time computation. Later, &lt;code&gt;constexpr&lt;/code&gt; and &lt;code&gt;consteval&lt;/code&gt; are, more than anything else, engineering optimizations along this trajectory. After all, eliminating constant factors is often a deeply tempting proposition.&lt;/p&gt;
&lt;p&gt;Obviously, the operands of operators are not necessarily used for mathematical computation. If we examine the substance of memory management, it is in fact the maintenance of allocation information through specific data structures. The practical meaning of a memory operation is simply to modify that ledger.&lt;/p&gt;
&lt;p&gt;This is where things become interesting. We all know that if a data structure needs to support convenient merging and modification, it is usually implemented with pointers, so as to avoid the cost of frequent copying. Moreover, in modern C++, cursor-based implementations are still, in essence, pointer-like implementations. In other words, hard-coding memory management into algorithmic logic is a pseudo-requirement; it should be handed uniformly to allocator policies through template metaprogramming. If courses on algorithms and data structures still insist on the three implementations of linear lists, then in my view, this is somewhat too pre-modern.&lt;/p&gt;
&lt;p&gt;Once this premise is clear, we can re-examine the inherent problem of pointer-based implementations: it is really a memory-access performance bottleneck caused by non-contiguity. The more fundamental question is: why do we need heap allocation in the first place? Because some forms of bookkeeping genuinely require runtime information.&lt;/p&gt;
&lt;p&gt;At this point, it should be clear what I am getting at. Hash-table-driven state machines, prefix trees for RESTful-style API routing, and so on: if the registered services do not need hot updates, then compile-time computation can be used to allocate fixed contiguous memory while preserving pointer semantics, thereby improving locality. The data can simply be loaded during initialization. Even if hot updates are required, as long as reserved space is used, or updates themselves are infrequent, this cost can still be pushed down substantially.&lt;/p&gt;
&lt;p&gt;Furthermore, if strategy-driven template metaprogramming is used here to decouple allocation logic and growth logic into the allocator, the price you pay is merely a little compilation time. What you may save, however, is an enormous amount of maintenance cost for the entire team.&lt;/p&gt;</content:encoded><category>Modern C++</category><category>Template Metaprogramming</category><category>Memory Management</category></item><item><title>Reddit Alt-Data Pipelines: Quantifying Memes into Market Signals</title><link>https://atelier.moesegfault.dev/en/blog/2025-10-05-1-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2025-10-05-1-en/</guid><description>Many quantitative teams really do scrape Reddit data and turn it into sentiment indexes; in that sense, memes, despair, and mania can all become observable market variables.</description><pubDate>Sun, 05 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The public-opinion dynamics on platforms such as Reddit, X, and Weibo are, in essence, delayed feedback systems: people overshoot in response to price movements, and then overcorrect afterward. In the vocabulary of cybernetics, this can almost be understood as a second-order oscillation system.&lt;/p&gt;
&lt;p&gt;The top and bottom of a market, then, are not necessarily only boundary conditions in a valuation model; they may also be moments when human collectives enter self-excited oscillation under nonlinear feedback. It sounds like a chaotic equation, but Reddit happens to be an observation window into that chaotic function: Reddit is one of the most typical experimental zones of globalized financial democratization, where everyone can speak, everyone can trade, and everyone can be wrong. Precisely for that reason, it often reveals the instant at which collective illusion takes shape earlier than any institutional research report.&lt;/p&gt;
&lt;p&gt;In fact, many quantitative teams really do scrape Reddit data and turn it into a sentiment index:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Post Volume&lt;/strong&gt;: a surge in posts -&gt; a surge in retail participation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Comment Tone&lt;/strong&gt;: the ratio of positive to negative sentiment -&gt; short-term bullish or bearish pressure.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Meme Frequency&lt;/strong&gt;: the frequency of phrases such as &quot;to the moon&quot; and &quot;diamond hands&quot; -&gt; the degree of bubble formation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Loss Posts&lt;/strong&gt;: a spike in posts of the &quot;my life is ruined&quot; type -&gt; a local-bottom signal.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One starting point for this line of thought was the GameStop frenzy, which brewed through 2019-2020 and erupted in 2021. Some data scientists found a significant positive correlation between WSB post volume and the price of GME. So they wrote small scripts using Python + PRAW + VADER sentiment analysis, then counted keyword frequencies and the positive/negative ratio of comments each day.&lt;/p&gt;
&lt;p&gt;Before long, they realized that this machinery was useful not only for watching GME, but also as an early indicator of retail capital momentum, a retail sentiment proxy. In other words, Reddit was no longer merely a landfill of trader emotion; it had become a seismograph for retail liquidity.&lt;/p&gt;
&lt;p&gt;Since 2021, related research has also appeared from institutions such as Columbia University, MIT, and the University of Chicago: the rate of change in the sentiment vectors of popular Reddit posts can predict small-cap volatility over the next 1-3 days; during the meme-stock period, comment depth was highly correlated with volatility; and when &quot;sarcastic optimism&quot; rises inside posts, it often signals the FOMO peak near the late stage of a rally.&lt;/p&gt;
&lt;p&gt;So this is no longer just meme play. It is the quantification of collective psychology in a very literal sense.&lt;/p&gt;
&lt;p&gt;At present, the mainstream algorithmic camps roughly fall into three groups:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Keyword Statistics&lt;/strong&gt;: computing term frequencies and sentiment scores for posts and comments, using methods such as TF-IDF + VADER/FinBERT.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Semantic Embeddings&lt;/strong&gt;: generating semantic vectors directly with embeddings and then clustering them, using tools such as Sentence-BERT / OpenAI Embeddings.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Network Dynamics&lt;/strong&gt;: constructing graphs from user interaction relations to analyze the speed of sentiment diffusion, using methods such as Graph Neural Networks / Diffusion Model.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At bottom, all these methods are pursuing the same thing: the &quot;second derivative&quot; of collective sentiment, meaning the rate of change of sentiment change. That is the most dangerous and seductive critical signal before the market turns.&lt;/p&gt;
&lt;p&gt;Never mind how rowdy WSB looks on an ordinary day, like the basement of financial markets. In practice, hedge funds have long been scraping data from Reddit, X, StockTwits, and the finance sections of Bilibili. They call this system:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alt-Data Pipeline&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;On Bloomberg terminals, this class of data source has gradually entered the mainstream. Put in an inelegant but rather accurate sentence: &quot;Institutions watch you post memes, then take the other side of your trade.&quot;&lt;/p&gt;
&lt;p&gt;The marvelous thing about quantifying subreddits is that it completes a passage: from &quot;human expression&quot; -&gt; &quot;collective sentiment field&quot; -&gt; &quot;market observable.&quot; It is almost a forced grafting of cognitive science onto quantitative finance. In a certain sense, it is the Fourier analysis of social consciousness.&lt;/p&gt;
&lt;p&gt;It also demonstrates a fact: modern finance is no longer merely the art of accounting. It is real-time simulation of psychology.&lt;/p&gt;</content:encoded><category>Quantitative Finance</category><category>Alternative Data</category><category>Market Sentiment</category></item><item><title>Concurrency and Parallelism: Dancing at the Edge of Computation</title><link>https://atelier.moesegfault.dev/en/blog/2025-10-01-1-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2025-10-01-1-en/</guid><description>From OpenMP and pthreads to CUDA, parallelization is not merely an expansion of toolchains, but a renewed interpretation of computational power, hardware limits, and formal models.</description><pubDate>Wed, 01 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Concurrency and parallelism are two concepts that are often placed side by side, and just as often conflated. Since the multicore era of the 2010s, algorithm design and architectural reasoning have long since moved beyond the classical single-threaded frame; even &lt;em&gt;Introduction to Algorithms&lt;/em&gt;, a canonical text in the field, has added discussion of parallel algorithms in its later updates, though some still argue that both the length and depth of that treatment remain far from sufficient.&lt;/p&gt;
&lt;p&gt;According to the definition I am more inclined to trust, concurrency means starting multiple tasks at the same time; parallelism means executing multiple tasks at the same time. Since the basic unit of CPU scheduling is the kernel thread (or lightweight process), using the process alone as the unit of measurement is not a sufficiently precise criterion for distinction. This is also why, apart from environmental isolation and runtime overhead, multiprocessing and multithreading often feel highly similar at the application layer.&lt;/p&gt;
&lt;p&gt;Concurrency has always been an especially painful region in practice. Interruptions and scheduling events that occur at unknown moments can easily give rise to bizarre race conditions; object lifetimes also become ambiguous, as if everything were being held together by the programmer&apos;s fragile mental model and the team&apos;s conventions. Especially when highly privileged kernel processes are moving back and forth, the whole scene acquires an almost cruel kind of beauty.&lt;/p&gt;
&lt;p&gt;Parallelization, by contrast, is one of the great tendencies of the age. From OpenMP and pthreads to the later emergence of CUDA, what stands behind it is in fact a renewed interpretation of computational power: the traditional RAM model, together with asymptotic complexity analysis, certainly guided algorithm design effectively for decades, but in the multicore era it inevitably shows its insufficiency. Models such as PRAM and LogP therefore emerged in response. These formal methods are of real value to practical engineering problems, because they describe the boundaries of capability and the frameworks within which those capabilities can be used.&lt;/p&gt;
&lt;p&gt;Of course, if we keep asking where this computational power ultimately comes from, the answer is still hardware progress. Multicore parallelization differs from instruction-level parallelism, superscalar execution, or vectorization; it is more a vast landscape drawn together by hyper-threading, push-pull migration and affinity, symmetric or heterogeneous multiprocessing, and related mechanisms. These are especially worth attending to in optimization, because they are not merely background knowledge: they are the performance boundary itself.&lt;/p&gt;
&lt;p&gt;Even today, when AI has opened an entirely new territory, distributed systems, systems programming, and high-performance computing remain the three mountains overhead. To put it with a little personal color and philosophical inclination: these fields are where computers dance at the boundary of &quot;the approximation of computation,&quot; and where the tension between formal methods and real systems reveals itself with particular intensity.&lt;/p&gt;</content:encoded><category>Computer Science</category><category>Concurrency</category><category>Parallel Computing</category></item><item><title>Cold-Starting Human Relations: Intimacy, Exchange, and the Visibility of Value</title><link>https://atelier.moesegfault.dev/en/blog/2025-09-29-1-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2025-09-29-1-en/</guid><description>Social life broadly has two forms: intimacy and exchange. Intimacy depends on contingency; exchange is the ordinary condition. The real question is not calculation, but how value becomes visible, felt, and reciprocal.</description><pubDate>Mon, 29 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A friend of mine has recently achieved some very real success. What unsettles her, however, is the self-consuming question: &quot;Why would people be so good to you for no reason?&quot; She said she has never been able to make sense of it.&lt;/p&gt;
&lt;p&gt;At the macro level, one reason is that Chinese people, in general, lack a sense of deservingness; another is that many excellent people are more or less prone to impostor syndrome. My own view is quite simple: whether others treat you well is, first of all, a matter of their judgment and mood. There is no need to perform a psychological audit on their behalf. And if you do in fact have value, then being treated well by others should instead be regarded as normal.&lt;/p&gt;
&lt;p&gt;I personally think social life broadly has two forms: one is intimacy, and the other is exchange. Intimacy almost entirely depends on contingency; exchange is the ordinary condition. The core of value exchange does not lie in how many material benefits one brings to others, but in whether one allows others to feel that they have gained something: intellectually, emotionally, and so on. To put it in more utilitarian terms, one has to give others a reason to choose cooperation.&lt;/p&gt;
&lt;p&gt;Many people are afraid of owing emotional debts, so they become constrained in both directions: after giving something to others, they also dare not take anything from them. This is a very common mistake. A good interpersonal relationship should be dynamically balanced. If it simply collapses toward either side, it is unhealthy in a symmetrical sense; one-sided giving in exchange for &quot;liking&quot; is not exchange. Even in traditional Chinese rural society, human ties were built on mutual indebtedness that could not be simply &quot;settled.&quot; In general, since I have chosen to give, I should also have the corresponding composure to receive.&lt;/p&gt;
&lt;p&gt;In most cases, one can choose to give first, because doing so releases a signal of cooperation. Relationships are always a matter of moving toward one another: I need to give others the opportunity to go further, and others also need to be willing to go further with me. Petty gains are fundamentally irrelevant. If one can thereby gain a partner for deep cooperation, the return is immeasurable.&lt;/p&gt;
&lt;p&gt;&quot;When virtue is complete, things arrive afterward.&quot; Of course, good wine still fears a deep alley, but that is mostly a matter of creating the occasion for dialogue. The more important question remains: what kind of value can I provide? A rare commodity naturally draws attention; when something is genuinely scarce, those little calculations are hardly worth mentioning. Nor should one fall into the mistake of relying on one&apos;s own ability, as if competence alone made everything possible. If something cannot give others a sense of gain, then even if one possesses it, it is not value, because it cannot be exchanged.&lt;/p&gt;
&lt;p&gt;The urge to lecture others is an absolute defect. I can share my feelings and views, but I must never use them to overwrite another person&apos;s structure of experience; that is a profound disrespect toward others. So if people do not ask, do not speak. What others do is, in itself, irrelevant. If they are people I care about, then doing my best is enough.&lt;/p&gt;
&lt;p&gt;After that, the remaining questions become purely technical problems: solve them by formula, and there is no great difficulty. In essence, it only depends on whether one has met the right people. I am, in fact, someone with very poor emotional intelligence. I do not have delicate emotional experiences, nor do I possess that kind of natural capacity for care. So in this area, there is truly not much that I understand.&lt;/p&gt;
&lt;p&gt;So social life is actually very boring: not because of boring petty calculations, but because it is sufficiently algorithmic, and in the end consists of techniques and operations. What is genuinely worth it is the important people: spending time accompanying them, spending time sensing what is there, understanding those stories that exceed embodied circumstance, and digesting the desire to share that flows out naturally. I personally think that the completion of career and intellect alone is not so worthy of desire. Perhaps richer experience is what is truly worth pursuing within a finite life. Money, knowledge, and people&apos;s stories and feelings are all only parts of that.&lt;/p&gt;</content:encoded><category>Self-Growth</category><category>Human Relations</category><category>Musings</category></item><item><title>Notes on a Paper Worth Reading</title><link>https://atelier.moesegfault.dev/en/blog/2025-09-13-1-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2025-09-13-1-en/</guid><description>This points to a transformation in the research paradigm. With PUCT (Predictor + UCB applied to Trees), the center of gravity shifts from solving problems to finding them, and toward designing evaluative measures that precisely reflect scientific goals.</description><pubDate>Sat, 13 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A paper I found genuinely suggestive: &lt;em&gt;&lt;a href=&quot;https://arxiv.org/abs/2509.06503v1&quot;&gt;An AI system to help scientists write expert-level empirical software&lt;/a&gt;&lt;/em&gt;. A few notes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Gemini&apos;s formulation is quite apt: the impact of a study depends, to a significant extent, on how it defines and frames the problem it claims to solve. To elevate a specific issue into a general challenge is a decisive step toward giving a research result wider force. The authors do not merely say that they have &quot;found a better code generation method for several benchmark tasks&quot;; instead, they claim to be &quot;accelerating the loop of scientific discovery.&quot; This difference in problem consciousness and narrative scale is precisely what separates a good paper from a top-tier one. Research should not stop at &quot;solving a problem.&quot; What matters just as much is learning how to frame the problem, generalize the solution, and design a persuasive evaluation strategy that substantiates the claim. The narrative architecture and evidentiary chain of a paper are no less important than the technical innovation itself.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Gemini&apos;s second point is also well judged: a profound contribution does not necessarily require inventing an entirely new theory or algorithm from scratch. It may equally arise from a new mode of composition: rearranging existing but powerful tools so that, together, they address a problem no single tool could plausibly reach. Researchers therefore need to preserve a cross-disciplinary field of vision and keep asking: what would happen if a strong technique from field A were applied to a canonical problem in field B? The capacity to discover new connections and generate new combinations is itself a vital source of innovation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;This looks less like an incremental advance than a transformation at the level of research paradigm. In the case of PUCT (Predictor + UCB applied to Trees), the center of gravity for this class of tasks moves from problem-solving to problem-finding, and toward the design of evaluative measures precise enough to reflect scientific goals. In the past, one could perhaps produce this kind of innovation by pre-positioning a dataset, or by controlling the definition of the standard, that is, the optimization target, and then grinding toward SOTA. Under the new trajectory, however, the lifecycle of that strategy has been sharply compressed. The ability to define the direction of optimization and open new optimization paths remains crucial in every era. But creative destruction has now arrived at the door: the research posture of serving as an executor captured by performance metrics, repeating 1 -&gt; 100 incremental innovation inside an existing paradigm, is no longer tenable. Pure execution cannot compete with an indefatigable AI system.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In practice, only large institutions can really afford to operate systems of this kind. For an individual, independently handling such a hyper-complex system is unrealistic in terms of both engineering burden and resource demand. Whoever first secures the computational infrastructure, data, and deployment pipeline for such AI systems may well command the next era of scientific production; this is, almost literally, the throne from which paradigms are set. Ultimately, researchers have to adapt to the alternation between old and new paradigms, and to the creative destruction that comes with it. A mode of research that merely accumulates publication counts and obeys supervisory authority is rapidly losing value. For individuals, then, genuinely AI-native capability is far more practical than another layer of conventional academic technique. Many still pretend not to see the elephant in the room, continuing old training regimes while treating AI only as a new topic for innovation and publication. But cycles and structural regularities do not readily submit to human preference.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We should also demystify quantifiable metrics. In the past, excessive reliance on them could perhaps be defended as a trade-off for efficiency. At the level of tools, however, we now have much better options. In any case, the transformation of evaluation standards is a fact one has to accommodate: no number of recruited executors can compete with someone capable of posing questions and exploring ambiguous territory. The repeated construction of standardized tests and selection mechanisms may appear reasonable on the surface; in the hands of certain obsolete sensibilities, however, it often does little more than stage Goodhart&apos;s Law again and again. So there is little point in complaining that the people or students one recruits are only good at taking tests, cannot get things done, and cannot translate research into practice. One should first ask how impoverished one&apos;s own judgment and taste have become.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</content:encoded><category>Paper Reading</category><category>AI Systems</category><category>Musings</category></item><item><title>A Deep Dive into Compile-Time Fibonacci Calculation</title><link>https://atelier.moesegfault.dev/en/blog/2025-09-08-1-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2025-09-08-1-en/</guid><description>The history of compiler optimization resembles a discipline of expanding what is available while reducing what is wasted: on one side, optimization algorithms evolve; on the other, we feed the compiler more information and thereby move the boundary of semantic constraint. From a modern C++ perspective, template metaprogramming should be returned to its proper role as an abstraction over families of processes and a tool for policy-driven design. Computing Fibonacci numbers with templates was, above all, a pre-C++11 detour taken under constraint.</description><pubDate>Mon, 08 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A common C++ &quot;interview question&quot; asks us to compute the Fibonacci sequence with &lt;code&gt;template&lt;/code&gt; and the machinery surrounding template metaprogramming. The implementation itself is not complicated:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;#include &amp;#x3C;iostream&gt;

template &amp;#x3C;unsigned int n&gt;
struct Calculator
{
    static const unsigned int value = Calculator&amp;#x3C;n - 1&gt;::value + Calculator&amp;#x3C;n - 2&gt;::value;
};

template &amp;#x3C;&gt;
struct Calculator&amp;#x3C;1&gt;
{
    static const unsigned int value = 1;
};

template &amp;#x3C;&gt;
struct Calculator&amp;#x3C;2&gt;
{
    static const unsigned int value = 1;
};

template &amp;#x3C;unsigned int n&gt;
const unsigned int fibonacci = Calculator&amp;#x3C;n&gt;::value;

int main(void)
{
    std::cout &amp;#x3C;&amp;#x3C; fibonacci&amp;#x3C;5&gt; &amp;#x3C;&amp;#x3C; std::endl;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The core lies in C++&apos;s characteristic mechanism for template argument deduction and matching. In effect, that mechanism gives us a form of branching: the compiler prefers the &quot;more suitable&quot; match, so we specialize the cases where &lt;code&gt;n&lt;/code&gt; is &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;2&lt;/code&gt; as the recursion&apos;s base cases.&lt;/p&gt;
&lt;p&gt;The same idea appears quite naturally in template partial specialization:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;#include &amp;#x3C;iostream&gt;

template &amp;#x3C;typename T&gt;
struct is_pointer
{
    static const bool value = false;
};

template &amp;#x3C;typename T&gt;
struct is_pointer&amp;#x3C;T *&gt;  // Partial specialization!
{
    static const bool value = true;
};

template &amp;#x3C;&gt;
struct is_pointer&amp;#x3C;decltype(nullptr)&gt;
{
    static const bool value = true;
};

template &amp;#x3C;typename T&gt;
const bool is_pointer_v = is_pointer&amp;#x3C;T&gt;::value;

int main(void)
{
    std::cout &amp;#x3C;&amp;#x3C; is_pointer_v&amp;#x3C;decltype(nullptr)&gt; &amp;#x3C;&amp;#x3C; std::endl;
    std::cout &amp;#x3C;&amp;#x3C; is_pointer_v&amp;#x3C;decltype(2)&gt; &amp;#x3C;&amp;#x3C; std::endl;
    std::cout &amp;#x3C;&amp;#x3C; is_pointer_v&amp;#x3C;decltype(&amp;#x26;std::cout)&gt; &amp;#x3C;&amp;#x3C; std::endl;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For &lt;code&gt;&amp;#x26;std::cout&lt;/code&gt;, C++ matches the more suitable template form &lt;code&gt;T *&lt;/code&gt;, and &lt;code&gt;value&lt;/code&gt; is therefore set to &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Of course, &quot;more suitable&quot; is only a convenient shorthand. At the level of the standard, C++ defines the deduction and matching process with strict and rather fine-grained rules.&lt;/p&gt;
&lt;p&gt;It is worth remembering an almost cruel law of software engineering: complexity does not disappear; it moves. This calculator, through template instantiation, transfers the complexity that would have belonged to runtime computation into compile time. In most cases, that is a defensible exchange. When we examine production code, we tend to reason in terms of asymptotic complexity: optimization is primarily concerned with growth rates, although user experience adds a less forgiving supplement to the doctrine: in many situations, constant-time improvements also deserve serious attention.&lt;/p&gt;
&lt;p&gt;Yet C++11, the point at which modern C++ begins in earnest, gives us a more direct tool for this kind of compile-time computation: &lt;code&gt;constexpr&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;What we were doing above was essentially a circuitous way to express the following function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;int fibonacci(int n)
{
    if (n == 1 || n == 2)
        return 1;
    else
        return fibonacci(n - 1) + fibonacci(n - 2);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The real bottleneck in the past was that the compiler did not know this computation ought to be moved into compile time, so we had to use &lt;code&gt;template&lt;/code&gt; to compel it to do the arithmetic. If we look at the compiler itself, its real strength lies in maintaining and exploiting type information. In a meaningful sense, compilation is the completion of a constructive proof, and the boundary of optimization is the boundary of the information available to the compiler. The more natural solution, then, is to provide that information explicitly and let the compiler perform the compile-time evaluation. That is where &lt;code&gt;constexpr&lt;/code&gt; enters.&lt;/p&gt;
&lt;p&gt;It &lt;strong&gt;suggests&lt;/strong&gt; to the compiler that the calculation be performed at compile time:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;#include &amp;#x3C;iostream&gt;

// With a constexpr function, evaluation can happen at compile time.
constexpr int fibonacci(int n)
{
    // Since C++14, constexpr function bodies may contain richer control logic,
    // making them structurally close to ordinary functions.
    if (n == 1 || n == 2)
        return 1;
    else
        return fibonacci(n - 1) + fibonacci(n - 2);
}

int main(int argc, char *argv[])
{
    // fibonacci(10) is a constant expression, so the compiler can evaluate it at compile time.
    std::cout &amp;#x3C;&amp;#x3C; fibonacci(10) &amp;#x3C;&amp;#x3C; std::endl; // After compilation, this becomes `std::cout &amp;#x3C;&amp;#x3C; 55 &amp;#x3C;&amp;#x3C; std::endl;`

    // It can also be used to define array sizes.
    int arr[fibonacci(6)] = {}; // Defines an array of size 8
    std::cout &amp;#x3C;&amp;#x3C; &quot;Array size: &quot; &amp;#x3C;&amp;#x3C; sizeof(arr) / sizeof(int) &amp;#x3C;&amp;#x3C; std::endl;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The problem, however, lies precisely in this &quot;suggestion.&quot; Just as C++ templates have recursion-depth limits, a &lt;code&gt;constexpr&lt;/code&gt; computation that is too deep, or a context in which the compiler cannot establish that the expression is constant, may still fall back to runtime evaluation. To remove that advisory character and require compile-time evaluation, one can use &lt;code&gt;consteval&lt;/code&gt;. Both facilities are ways of giving the compiler information and thereby expanding the space in which optimization can operate.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is worth isolating the complexity of the Fibonacci computation itself. In the template metaprogramming example, each &lt;code&gt;Calculator&amp;#x3C;n&gt;&lt;/code&gt; is a distinct type. Because the compiler maintains type information, it stores those instantiations and does not repeatedly recompute identical substructures. The complexity is therefore not &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;msup&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;/msup&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;O(2^n)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.6644em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; but &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;O(n)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;: each case from 1 through n only needs to be computed once, and random access in the usual RAM model is treated as constant time. In the later &lt;code&gt;constexpr&lt;/code&gt; approach, modern mainstream compiler implementations, when evaluating a constant expression under sufficiently high optimization settings, typically use memoization-like machinery to avoid redundant work as well. In practice, then, the compile-time cost of recursive constant evaluation such as &lt;code&gt;fibonacci(10)&lt;/code&gt; is also closer to linear complexity, &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;O(n)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, than to an exponential explosion.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Of course, C++17 also gave &lt;code&gt;constexpr&lt;/code&gt; something like a compile-time branching form: &lt;code&gt;if constexpr&lt;/code&gt;. It performs the conditional check at compile time and discards the invalid branch outright.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;#include &amp;#x3C;iostream&gt;
#include &amp;#x3C;type_traits&gt;

template&amp;#x3C;typename T&gt;
void print_info(T value) 
{
    if constexpr (std::is_pointer_v&amp;#x3C;T&gt;) 
    {
        // If T is not a pointer, this entire block, including the braces,
        // is discarded by the compiler and never enters the instantiation path.
        // Therefore, even if T is int, syntax such as *value will not cause compilation to fail.
        std::cout &amp;#x3C;&amp;#x3C; &quot;It&apos;s a pointer to: &quot; &amp;#x3C;&amp;#x3C; *value &amp;#x3C;&amp;#x3C; std::endl;
    } 
    else 
    {
        // Conversely, if T is a pointer, this block is discarded.
        std::cout &amp;#x3C;&amp;#x3C; &quot;It&apos;s a value: &quot; &amp;#x3C;&amp;#x3C; value &amp;#x3C;&amp;#x3C; std::endl;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Taken together, this reflects C++&apos;s broader tendency to move more semantics forward into compile time.&lt;/p&gt;
&lt;p&gt;Of course, if one insists on building calculators out of notoriously unreadable template metaprogramming, or simply wants to test the edges of the language, &lt;code&gt;constexpr&lt;/code&gt; still has a useful role to play: it can construct compile-time objects, offering a substantial improvement in both expressiveness and readability.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;#include &amp;#x3C;iostream&gt;

struct Point 
{
    double x, y;

    // Step 1: provide a constexpr constructor.
    // C++11 required the constructor body to be empty, allowing only an initializer list.
    // C++14 and later relaxed this constraint, allowing more complex logic in the body.
    constexpr Point(double x_val, double y_val) : x(x_val), y(y_val) {}

    // Step 2: member functions intended for compile-time calls must also be constexpr.
    constexpr double length_sq() const 
    {
        return x * x + y * y;
    }
    
    // Step 3 (implicit): Its destructor must be trivial.
    // The default destructor is trivial, so no explicit definition is needed.
    // ~Point() = default;
};

int main() 
{
    // Create Point objects at compile time.
    constexpr Point p1(3.0, 4.0);
    constexpr Point p2(5.0, 12.0);

    // Call a member function at compile time to compute another constant.
    constexpr double len_sq = p1.length_sq(); // The compiler calculates this as 25.0

    // Use this compile-time result to define an array.
    int my_array[static_cast&amp;#x3C;int&gt;(len_sq)]; // Creates an array of size 25
    std::cout &amp;#x3C;&amp;#x3C; &quot;Array size: &quot; &amp;#x3C;&amp;#x3C; std::size(my_array) &amp;#x3C;&amp;#x3C; std::endl;

    // These objects can also participate in compile-time operations.
    constexpr Point p3(p1.x + p2.x, p1.y + p2.y); // p3 is (8.0, 16.0)
    
    std::cout &amp;#x3C;&amp;#x3C; &quot;p3.x = &quot; &amp;#x3C;&amp;#x3C; p3.x &amp;#x3C;&amp;#x3C; std::endl; // After compilation, this line might become `std::cout &amp;#x3C;&amp;#x3C; &quot;p3.x = &quot; &amp;#x3C;&amp;#x3C; 8.0 &amp;#x3C;&amp;#x3C; std::endl;`
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In conclusion, the history of compiler optimization resembles a discipline of expanding what is available while reducing what is wasted: on one side, optimization algorithms improve; on the other, we provide the compiler with more information and thereby move the boundary of semantic constraint. From a modern C++ perspective, template metaprogramming should still be returned to the proper role of &lt;code&gt;template&lt;/code&gt;: abstracting families of processes in service of policy-driven design. Computing Fibonacci numbers with templates was mostly a pre-C++11 detour taken under constraint, and recursive template instantiation remains one of the wellsprings of the notorious opacity people call &quot;template black magic.&quot;&lt;/p&gt;</content:encoded><category>Modern C++</category><category>Templates</category><category>Compile-Time Computation</category></item><item><title>Notes Toward a Critique of University God-Making</title><link>https://atelier.moesegfault.dev/en/blog/2025-09-07-1-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2025-09-07-1-en/</guid><description>Just as academic taste requires long cultivation, the discernment of demand also contains a great deal of tacit knowledge, and it too must be trained. Yet this is precisely what the narrative sustaining the university refuses to provide: it teaches you how to &apos;solve problems,&apos; but not how to &apos;find problems.&apos; And the ability to &apos;find problems&apos;—to discover and define valuable questions—will be far more precious in the future than the ability to &apos;solve them.&apos;</description><pubDate>Sun, 07 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A central problem today is that the machinery of &quot;god-making&quot; within universities has become remarkably severe. Stories such as an entire dormitory securing graduate-school recommendations, students copying code by hand, or yet another undergraduate publishing in a top conference or journal are quickly packaged into narratives fit for veneration. Around the age of twenty, one is already unusually susceptible to the production of myths and idols; immediately afterward comes the most plastic decade of one&apos;s life. The resulting atmosphere is therefore molded into an almost coercive consensus: if you do not secure graduate admission, pursue a PhD, or enter a major tech firm, your life has somehow already failed.&lt;/p&gt;
&lt;p&gt;Nor do we ordinarily encourage the Kantian spirit of &quot;dare to know.&quot; In certain contexts, the pursuit of knowledge itself has even come to resemble a kind of transgression. Everything tends to be justified through seniority, experience, and title. Universities also rarely encourage the Socratic form of education that, through dialogue and questioning, &quot;guides people to discover the knowledge within themselves.&quot; Instead, the supervisor is installed as the subject of education, while the student is positioned as the object of reception and indoctrination. Moreover, many people formed within STEM are accustomed to objects that are quantifiable and falsifiable, yet rarely extend the same reflective pressure to the question of meaning.&lt;/p&gt;
&lt;p&gt;The more decisive issue is that we all understand the supply-and-demand relation in talent recruitment. With undergraduate and graduate credentials increasingly inverted in value, and with master&apos;s programs being extended, the number of available positions becomes the determining factor under conditions of general oversupply. In other words, under the present macro environment, demand determines the price of your labor. A typical supply-side inference then follows: one should increase the scarcity of one&apos;s credentials; or, for those who think a little further, increase the scarcity of one&apos;s abilities.&lt;/p&gt;
&lt;p&gt;It is precisely here that the value of first-principles thinking becomes visible. One can in fact push the question further: does demand exist only in the positions offered by major tech companies? Only in research institutes and faculty posts? Ultimately, these are merely explicit forms of demand. What, then, of the demands that have not yet been adequately named? We are accustomed to the narrative of acquiring degrees, polishing skills, and then entering one organization or another as an employee; yet we rarely ask in earnest why, in an era supposedly driven by demand rather than technology, the scarcity of knowledge, skills, and even symbolic capital such as degrees is placed above a cultivated taste for demand itself. Just as academic taste requires long cultivation, the discernment of demand also contains a great deal of tacit knowledge, and it too must be trained. Yet this is precisely what the narrative sustaining the university refuses to provide: it teaches you how to &quot;solve problems,&quot; but not how to &quot;find problems.&quot; And the ability to &quot;find problems&quot;—to discover and define valuable questions—will be far more precious in the future than the ability to &quot;solve problems.&quot; This also explains the root of the claim that &quot;a degree does not equal ability&quot;: today, your price is no longer primarily governed by your own scarcity, but by the demand of those who might employ you.&lt;/p&gt;
&lt;p&gt;A participant in Adventure X once lamented on their blog that universities are lifeless. The judgment is not exaggerated. In an environment that privileges indoctrination over discussion, reproduction over creation, and publication over implementation, one should hardly expect anything genuinely vital to grow. Even the practical value of many papers in top conferences and journals remains suspended in a rather ambiguous state of meaninglessness. All this is unfolding at a moment when AI continues to rise and compress the value of human proficiency: when humans cannot outperform AI on algorithm problems, and basic code has become nearly abundant, this fortress-like order of evaluation appears increasingly anachronistic.&lt;/p&gt;</content:encoded><category>Daily Rants</category><category>AI-native</category><category>New Possibilities</category></item><item><title>A Critique of the University&apos;s &apos;AI Practice Course&apos;</title><link>https://atelier.moesegfault.dev/en/blog/2025-09-06-1-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2025-09-06-1-en/</guid><description>The current rush into deep learning resembles the posture of an investor, still far from the self-consciousness of an AI-native believer.</description><pubDate>Sat, 06 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If the course begins by asserting authority through intimidation, with the atmosphere of a sealed institutional vat, then I have no interest in participating. A group of people who have not even subscribed to ChatGPT Plus are gathering to conduct an &quot;AI practice&quot; course; beyond a review of classical deep learning and guided readings of post-Transformer literature, I can scarcely imagine what substantive content they could offer. If my aim is simply to acquire knowledge, I will of course turn to AI. Competent prompt engineering is, in effect, like having two PhD candidates alternate in providing intellectual labor on my behalf.&lt;/p&gt;
&lt;p&gt;For those who do not aspire to conduct research in NLP / CV / RL, the central task is not to immerse themselves in esoteric academic assignments and then serve as executors of application-layer transfer, thereby becoming academic human capital. What truly matters is how to integrate AI as a tool into one&apos;s own workflow; this is what AI-native is meant to signify.&lt;/p&gt;
&lt;p&gt;The pathology of most such &quot;practices&quot; lies precisely here: they regard AI merely as a local patch upon existing paradigms, rather than as the opening of a new interaction paradigm altogether. Hence the familiar contradiction: companies claim to seek candidates who can use AI tools well, while simultaneously banning AI in structured interviews.&lt;/p&gt;
&lt;p&gt;The current rush toward deep learning is less the conviction of a believer than the acquisitive posture of an investor; it remains far from the self-consciousness of an AI-native believer. And as I have argued before, such stampedes are often irrational. Even a modest familiarity with the consumer-side landscape and community practice would be enough to temper this near-fanatical imagination.&lt;/p&gt;</content:encoded><category>Daily Rants</category><category>AI-native</category></item><item><title>Some Advice for CS Undergrads (Free &amp; Beginner Version)</title><link>https://atelier.moesegfault.dev/en/blog/2025-09-06-2-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2025-09-06-2-en/</guid><description>A low-cost starter protocol for young CS people, myself included.</description><pubDate>Sat, 06 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A preliminary, low-cost protocol for young CS people, myself included (Free &amp;#x26; Beginner ver.):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Block CSDN at the level of information intake.&lt;/li&gt;
&lt;li&gt;Develop the reflex of asking DeepSeek, Kimi, and Qwen first whenever a problem appears.&lt;/li&gt;
&lt;li&gt;Avoid casual Zhihu browsing, especially under the flattering pretext of &quot;broadening one&apos;s horizons.&quot;&lt;/li&gt;
&lt;li&gt;For news apps, prefer NetEase News over Weibo.&lt;/li&gt;
&lt;li&gt;Learn the mechanics of recurring investments through Alipay.&lt;/li&gt;
&lt;li&gt;Obtain and maintain a sufficient set of debit cards and, where feasible, credit cards.&lt;/li&gt;
&lt;li&gt;For professional knowledge, anchor yourself in established computer science book series and Bilibili re-uploads; do not chase dubious shortcuts.&lt;/li&gt;
&lt;li&gt;Secure a passport, a Hong Kong/Macau travel permit, and as many visas as practical.&lt;/li&gt;
&lt;li&gt;Learn Outlook and To Do, or equivalent systems for email, calendar, and task management.&lt;/li&gt;
&lt;li&gt;Understand and become able to use what the Microsoft 365 suite contains; purchase is not mandatory.&lt;/li&gt;
&lt;li&gt;Use GitHub aggressively for code, along with the bundled Copilot Free and *.github.io.&lt;/li&gt;
&lt;li&gt;For entertainment, use Bilibili, Xiaohongshu, and Douyin; do not let leisure become another source of psychic attrition.&lt;/li&gt;
&lt;li&gt;Install a Linux virtual machine (direct host installation is not advised if gaming still matters), and grow accustomed to the dark terminal rather than delegating everything to an IDE.&lt;/li&gt;
&lt;li&gt;In China, high-quality information appears on Douban, WeChat Official Accounts, and Zhihu, but with a very low signal-to-noise ratio; enter with discipline.&lt;/li&gt;
&lt;li&gt;Keep some distance from Xianyu, while learning to use the unconventional mechanisms on Xianyu and Taobao in their proper places, so that a compliance-oriented sensibility can take shape.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is the extent of the list for now. Its cognitive and financial costs are low; the difficulty lies mainly in operational execution. With enough flexibility, however, paths tend to remain available.&lt;/p&gt;</content:encoded><category>Daily Rants</category><category>Career Advice</category></item><item><title>A Few Objections to Bilibili&apos;s Recommendation System</title><link>https://atelier.moesegfault.dev/en/blog/2025-09-03-1-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2025-09-03-1-en/</guid><description>I admit that I have not used Bilibili frequently enough to train my account profile properly; nevertheless, its personalization algorithm still feels remarkably crude. It may capture my general persona and field of interest, but it fails to match the corresponding depth and information density, remaining instead at the level of tag similarity. The signal-to-noise ratio is too low, and the experience is predictably poor.</description><pubDate>Wed, 03 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;My Bilibili recommendation feed is saturated with things I have no wish to watch, and at the moment this leaves me distinctly displeased:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;The interview-question videos should know when to stop. Can one really claim to understand concurrent programming while discussing application-layer spinlocks without even considering interrupts? As for producing linked-list code that cannot determine whether a cycle or an intersection exists, that points to a painfully weak engineering foundation. If I encountered such a collaborator on a team, I would either make them repair their data-structure fundamentals or simply ask them to leave.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Videos about algorithm problems are no more appealing to me, especially when they promote the idea that one need not learn something because it is &quot;not tested&quot; or &quot;rarely tested.&quot; That argument steps almost deliberately into my zone of irritation. What I want is a systematic education grounded in &lt;em&gt;Discrete Mathematics and Its Applications&lt;/em&gt; and &lt;em&gt;Introduction to Algorithms&lt;/em&gt;, then supplemented by training in parallel algorithms, not a mere accumulation of problem types and solution templates.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Videos on modern C++ and systems details are even more likely to trigger my nearly severe standards of judgment. I have very little interest in the surface form of a given syntax; what I want is an analysis of its evolutionary trajectory and internal value, not a parade of flashy features or another heap of scattered, unstructured facts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When I finally encounter a video that seems interesting, I click in only to discover that it is a re-uploaded piece of content, now wrapped in an AI-generated machine-translated voiceover. I leave immediately. What, precisely, is the point of consuming machine-translated YouTube replicas on Bilibili?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Why is there such an overflow of videos on research methodology and academic topics, especially AI? I do not have a supervisor to placate. The platform cannot classify me as a graduate student merely because I occasionally clicked on a few related videos, and then proceed to push an endless stream of ambiguous deep-learning content and paper explainers at me.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Some of the math videos are genuinely interesting, but what the system mainly recommends to me is graduate-entrance-exam and college-entrance-exam mathematics, to the point that I begin to suspect the algorithm is, in some sense, &quot;insulting&quot; me. I have no interest in piling up complex integrals. Even if one pushes hand-computation techniques to their limit, they still will not outperform symbolic computation; yet when asked to discuss the history of mathematics, proof, or abstraction, such content often has nothing to say.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Then there is a class of videos that use phrases like &quot;985/211&quot; or &quot;high school student does X&quot; as their title-level selling point. I have little interest in these either. The value of a person&apos;s thought and knowledge does not derive from their title, and the viability of their claims should be tested jointly by reality and logic. As for narratives that use age to dramatize talent, they are frankly rather dull; those people have probably never experienced how uncomfortable a genuine mismatch between age and cognition can be. Instead of spending that time reinventing wheels in isolation, they would do better to admit their limits and look at the problem from the shoulders of their predecessors.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Just when I finally scroll to a gaming video or a female creator I might actually want to watch, I find myself surrounded by cybersecurity content. My interest in cryptography and network security is genuinely limited, and professional matters should be left to professionals. My taste, or more precisely my instinctive judgment, evaluates things from the perspective of performance and systems, not security. I may be able to do some high-performance computing and systems programming, but I am not suited to becoming a security expert.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I admit that I have indeed used Bilibili too little to train my account profile properly; nevertheless, its personalization still appears far too crude. It may be able to infer &quot;what kind of person I am&quot; and &quot;roughly which direction I face,&quot; but it cannot go on to match sufficient content depth or information density. It remains mechanically trapped at the level of tag similarity. The signal-to-noise ratio is too low, and the resulting experience is naturally poor.&lt;/p&gt;</content:encoded><category>Daily Rants</category><category>Bilibili</category></item><item><title>The Gap Between Ideal and Reality in Algorithm Learning</title><link>https://atelier.moesegfault.dev/en/blog/2025-08-28-1-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2025-08-28-1-en/</guid><description>Pure formal models are often a projection of reality, a selective reflection. Algorithms, as logical models, also face scrutiny regarding their scope of application in the real world.</description><pubDate>Thu, 28 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Algorithms, along with data structures, are nearly ubiquitous in the computational world: from an ordinary function call to routing and load balancing in computer networks. From a sufficiently theoretical perspective, an algorithm is first of all a logical model, while concrete code is only its translation into a particular programming language. More radical discussions may take assembly as a unified baseline in order to exclude implementation-level noise as far as possible, but the more common idiom remains pseudocode: sequence, loops, and conditionals already carry considerable expressive power.&lt;/p&gt;
&lt;p&gt;Our general impression of algorithms is often centered on asymptotic complexity analysis, especially under the RAM model (Random Access Machine model). This simple yet powerful model has guided algorithm design for decades, remained remarkably robust in the multi-core era after the 2010s, and is still one of the core concerns of undergraduate education today. Yet a purely formal model is often only a projection of reality, a selective reflection. Algorithms, as logical models, must therefore have their scope of application carefully delimited in practice. Asymptotic complexity analysis, for instance, describes the growth trend of an algorithm&apos;s time consumption under an ideal model, but in some scenarios it does not strictly correspond to empirical performance.&lt;/p&gt;
&lt;p&gt;The most direct divergence comes from device I/O. A single disk I/O is enough to force algorithm design in an entirely different direction. If the model we adopt consists only of one computational unit, one read/write head, and an infinite tape, then a B-tree may not display an overwhelming performance advantage over a binary tree, even if the latter is usually equipped with balancing constraints. In database systems, however, a B-tree can substantially reduce the number of queries; its root can even remain resident in main memory, and it naturally supports range access, which gives it an enormous engineering advantage.&lt;/p&gt;
&lt;p&gt;Another issue worth considering is caching. The temptation of an L1 cache hit is almost impossible to ignore. Compared with a separate chaining hash table, for example, which is common in competitive programming, an open addressing hash table may be faster in certain scenarios precisely because it avoids several pointer accesses. This is especially true of linear probing: although clustering is a serious problem, it also brings the advantage of CPU prefetching.&lt;/p&gt;
&lt;p&gt;Then there are complex concurrent environments. Algorithms and data structures that perform well in a serial model may, once placed in a concurrent setting, suffer significant degradation if straightforward locking introduces lock contention. The proper configuration of memory ordering also presents a substantial challenge. The more extreme case is the repertoire of techniques required to implement lock-free data structures. Concurrent programming already occupies a rather ambiguous territory, and its practical reliability often rests on guarantees supplied by a sequence of primitives. The aspiration toward lock-free programming is therefore richly idealistic, but at the operational level it is often almost brutally austere.&lt;/p&gt;
&lt;p&gt;More often, algorithmic performance is not the only metric. Maintaining a dynamically evolving system is far more difficult than producing a prototype. As the preface to the first edition of &lt;em&gt;Structure and Interpretation of Computer Programs&lt;/em&gt; states bluntly: &quot;programs must be written for people to read, and only incidentally for machines to execute.&quot; If optimizing an algorithm substantially damages overall readability, even making the code nearly unreadable to others, the trade-off must return to the team&apos;s condition and actual requirements. We do not need to pay a cost far beyond its value for a marginal gain. Although this situation is not especially common (because most of the time we are simply applying algorithms and design ideas inherited from predecessors), every optimization still deserves vigilance.&lt;/p&gt;
&lt;p&gt;Handling algorithms in reality is not as idealized as solving algorithmic exercises; the optimization target is not necessarily performance. Real-time systems, for instance, often prioritize perceived user experience rather than throughput. In the broader engineering context, what we face is usually a field of trade-offs and balances. In algorithmic exercises, producing multiple solutions to a single problem may train one&apos;s thinking; in reality, choosing which solution to adopt is itself a sufficiently difficult challenge. This leads to a deeper issue: if we examine the matter from an architectural perspective, the central task is not to recognize a pattern in an idealized environment and then select a familiar algorithm to solve it.&lt;/p&gt;
&lt;p&gt;Every field has a large body of algorithms adapted to its own context; there is no such thing as the strongest or most efficient algorithm in the abstract. Learning algorithms is not a matter of accumulating enough techniques to cover enough classes of problems, but of grasping patterns of algorithmic design. Many algorithms appear frequently in competitive programming not necessarily because they are well suited to real use, but because they are well suited to being organized as contest problems. Take the Red-Black Tree as an example: I use it far more often in daily work than dynamic programming, since every operation on &lt;code&gt;std::set&lt;/code&gt; and &lt;code&gt;std::map&lt;/code&gt; is backed by a Red-Black Tree implementation. When a standard itself becomes the optimization target, caution is especially necessary. Standardized education since the industrial era, in substance, establishes a standard component and evaluates individuals according to how closely they approximate it. If the contest is this kind of generalized ability over a particular class of tasks, I do not believe human beings can outcompete Large Language Models.&lt;/p&gt;</content:encoded><category>Algorithm Learning</category><category>Data Structures</category></item><item><title>AI Model Selection: Domestic Solutions and Open-Source Alternatives</title><link>https://atelier.moesegfault.dev/en/blog/2025-08-26-1-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2025-08-26-1-en/</guid><description>There is no absolute perfection, only contextual suitability; to move along the boundary between real-world constraints and technical possibility is precisely the charm of computer science.</description><pubDate>Tue, 26 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Although top-tier flagship models such as ChatGPT, Claude, and Gemini are effectively unavailable in many settings, and corporate or team deployments must still contend with severe compliance constraints, domestic solutions and open-source alternatives are far from irrelevant. They may not yet reach the comprehensive level of those closed flagship systems, but across a wide range of tasks they are already sufficiently capable, and their cost structure is unusually attractive.&lt;/p&gt;
&lt;p&gt;DeepSeek has released its latest v3.1, continuing the understated pattern it established in May, when it updated the R1 weights without changing the version number. Although 3.1 has also been criticized as a benchmark-optimized &quot;exam taker&quot; whose real-world behavior is less stable than its scores suggest, its low price, its demystification of the reasoning paradigm, and its speed always wins engineering instinct all reveal a distinctive sense of technical taste. The question is less whether the model is universally capable than whether it is placed in the right context; for API-based daily use and general-purpose tasks, it is already quite composed.&lt;/p&gt;
&lt;p&gt;For coding productivity, Kimi K2&apos;s strong performance in agentic abilities may in fact make it the more compelling practical choice. A mature setup that combines the CLI interaction pattern of tools such as Claude Code with Kimi K2 already offers a robust compromise between price and performance. At the same time, the friction of a Claude Pro subscription, together with its demanding network and payment requirements, forms a de facto barrier to entry. Much like Europe&apos;s excessively cautious safety regime, &quot;Constitutional AI&quot; can sometimes appear rather tightly bound.&lt;/p&gt;
&lt;p&gt;Another major coordinate in domestic open-source models is Qwen, which, alongside Gemini, has been regarded as something of a managerial miracle; Meta&apos;s LLaMA, by contrast, set a precedent that is not especially worth admiring. Qwen&apos;s embedding models have long been a reliable choice. If one is building a Retrieval-Augmented Generation (RAG) system, or a vector database for a broader class of tasks, they deserve to be considered near the top of the list.&lt;/p&gt;
&lt;p&gt;Another direction worth watching is performance-sensitive workloads: OpenAI has released its own open-source model, gpt-oss, whose capabilities reach the level of o4-mini and even o3-mini. This is not a modest position. Even the weight-updated DeepSeek-R1-0528 still sits at some distance from o4-mini, another reasoning model, giving the strange impression of a floor that exceeds someone else&apos;s ceiling. For scenarios with explicit performance requirements, purchasing cloud services to deploy this open-source model is therefore a highly pragmatic path.&lt;/p&gt;
&lt;p&gt;For needs that are narrow in scale but entirely real, Gemma 3n offers a different answer. This mobile-first open-source model is almost counterintuitive: even its aggressively compressed sub-1B parameter version still preserves multimodal capability. For mobile computing and real-time translation, this is a remarkably unambiguous blessing.&lt;/p&gt;
&lt;p&gt;In conclusion, by August 2025, the debate between open-source and closed-source models had already been settled the previous year in a direct and rather overwhelming fashion. Yet this does not prevent us from using flexible engineering techniques and comparatively rigorous academic methods to construct systems of our own. For instance, the paper &lt;em&gt;&lt;a href=&quot;https://arxiv.org/html/2505.19797v1&quot;&gt;The Avengers: A Simple Recipe for Uniting Smaller Language Models to Challenge Proprietary Giants&lt;/a&gt;&lt;/em&gt; uses clustering algorithms to organize open-source models and achieves results surpassing GPT-4.1; in mechanism, it resembles an explicit Mixture of Experts (MoE) architecture. It continues to illuminate the old engineering lesson: there is no absolute perfection, only contextual suitability. To move along the boundary between real-world constraints and technical possibility is precisely the charm of computer science.&lt;/p&gt;</content:encoded><category>Model Selection</category><category>AI Engineering</category><category>Open-Source Models</category></item><item><title>Why Does the Empowerment of AI Seem Ineffective?</title><link>https://atelier.moesegfault.dev/en/blog/2025-08-25-2-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2025-08-25-2-en/</guid><description>AI has already become a technology with substantial barriers, far removed from a toy-like or student-level practice.</description><pubDate>Mon, 25 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Why might the empowering effect of AI still feel indistinct, as if this so-called new quality productivity remains just beyond your grasp?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The ability to connect reliably to AI tools:&lt;/strong&gt; IP constraints, network conditions, and stable accounts are already enough to filter out countless people.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The ability to subscribe to Plus tiers:&lt;/strong&gt; Willingness to pay, capacity to pay, and access to payment channels form a second layer of material barriers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The ability to distinguish model choices and functional boundaries:&lt;/strong&gt; Faced with a sprawling model matrix (currently 8 model options and 6 feature options), along with memories, Projects, reference all chats, connectors, and related features, countless people are stopped before they even get past the interface.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The ability to practice prompt engineering:&lt;/strong&gt; Customize models, project instructions, and the context management of each conversation are, in practice, ongoing tests of expression, structure, and task decomposition.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The ability to internalize the habit of using AI:&lt;/strong&gt; Turning &quot;ask AI first&quot; into a default response to problems, bringing AI into life, academic work, and engineering, and accumulating a sufficiently long history of conversations have defeated countless people in their own right.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The ability to ask good questions:&lt;/strong&gt; Academic taste, engineering intuition, and one&apos;s own cognitive architecture determine whether AI becomes a genuine amplifier or merely a more elaborate search box.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The ability to build one&apos;s own AI applications:&lt;/strong&gt; Local deployment, API calls and hyperparameters, custom applications, Retrieval-Augmented Generation (RAG), and framework selection together mark the divide between user and builder.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All I can say is that AI has already become a technology with substantial barriers, far removed from a toy-like or student-level practice. Used well, it can make one &quot;unmatched below the doctoral level&quot;; that is not an exaggeration. The phrase &quot;PhD-level AI&quot; may still carry a degree of rhetoric, but a person compounded by the super-leverage of AI is a different configuration altogether.&lt;/p&gt;</content:encoded><category>AI-native</category></item><item><title>Concepts in C++: Returning Algebraic Proofs to the Compiler</title><link>https://atelier.moesegfault.dev/en/blog/2025-08-25-3-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2025-08-25-3-en/</guid><description>A concept is not merely a more respectable syntax for templates; it is a way of handing algebraic-structure information to the compiler.</description><pubDate>Mon, 25 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;As an aside, once duck typing comes up, it is hard not to think of &lt;code&gt;concept&lt;/code&gt; in C++. As a strongly statically typed language, C++ has long allowed its type system to be understood as a kind of set-theoretic modeling: declaring the fields of a class is declaring the constitution of elements in a set, approximately the specification of a tuple; declaring functions, methods, and overloaded operators is defining operators over those sets. Classical terminology distinguishes procedures from functions, but in my view a procedure is, in essence, also a mapping over program state, or over some local fragment of state, so refusing to draw a hard boundary is quite reasonable. One might even say that this is not multiset modeling either: in the C++ object model, distinct complete objects must generally remain distinguishable by address, and even an empty object occupies at least one byte. A small anecdote: when I first saw &lt;code&gt;private&lt;/code&gt; inheritance used to implement a has-a relationship, I thought it was needless ornamentation taking the long way around; only later did I understand the point of empty base optimization (EBO): saving that one byte, and thereby avoiding a cascade of alignment deficits, is indeed rather delicious. C++&apos;s highly distinctive template mechanism, before all the sorcery of &lt;code&gt;static reflection&lt;/code&gt;, type deduction, compile-time computation, and related techniques, was after all intended for generic programming; at a more abstract level, generic programming is the extraction of algebraic processes from a class of procedures. That, in turn, requires the programmer to check whether the set they have defined satisfies the algebraic properties required by the process. A certain fashionable doctrine says that writing code, especially waiting for compilation to succeed, is in fact a form of constructive proof: just as one must prove that a given set satisfies the field axioms before one is entitled to use the properties of a field. In the ancient period, which is to say before &lt;code&gt;concept&lt;/code&gt;, the responsibility for maintaining algebraic structure was largely assigned to the programmer&apos;s mind; the compiler, meanwhile, instantiated and deduced with an almost cold indifference, and when it failed, emitted unreadable template scripture. Now that &lt;code&gt;concept&lt;/code&gt; exists, what it really does is provide the compiler with information about algebraic structure: the compiler can first prove or refute the relevant propositions at the level of definition, which is an enormous release of cognitive load. Many techniques, such as extension-style qualifiers like &lt;code&gt;restrict&lt;/code&gt;, the &lt;code&gt;volatile&lt;/code&gt; keyword, and language features like attributes, are likewise ways of supplying the compiler with additional information, keeping the situation from sliding further into the uncontrollable. A semantic constraint, in the end, is nothing other than a rewriting of the boundary of information.&lt;/p&gt;</content:encoded><category>Modern C++</category><category>Type Systems</category></item><item><title>Vibe Coding: Forging a Standard-Library-Flavored Stack in 40 Minutes</title><link>https://atelier.moesegfault.dev/en/blog/2025-08-25-1-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2025-08-25-1-en/</guid><description>GPT-5 shows a genuine command of interfaces, type constraints, and allocator semantics.</description><pubDate>Mon, 25 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Where, precisely, does GPT-5&apos;s engineering competence now stand?&lt;/p&gt;
&lt;p&gt;Rather than staging the question rhetorically, here is the artifact produced after a 40-minute collaboration with it.&lt;/p&gt;
&lt;p&gt;The code should, in principle, be released under GPLv3.0. Since I cannot conveniently create a GitHub repository and provide a copy at the moment, the license text is available here: &lt;a href=&quot;https://www.gnu.org/licenses/&quot;&gt;https://www.gnu.org/licenses/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The prompts used during the exchange are as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-prompt&quot;&gt;Let us implement a Stack class targeting C++23.
1. Use `template &amp;#x3C;typename... Types&gt;` together with `std::variant` and `std::visit` to address alignment and type-safety concerns.
2. Support standard library-style iterators.
3. Use `std::construct_at` and `std::destroy_at` to manage object lifetimes manually and avoid unnecessary overhead.
4. Remain compatible with `pmr` and `allocator`, allowing the allocation strategy to be changed.
5. Use `concept`s to state the relevant requirements explicitly, preventing the design from collapsing into template-metaprogramming occultism.
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-prompt&quot;&gt;The current implementation is a solid basis; let us iterate on it:
1. Check for issues related to template parameter-pack expansion.
[compiler log ...]
2. Unless strictly necessary, use alternative logical operators such as `and` and `or` instead of old C-style forms.
3. Use Doxygen-style comments, with explanations detailed enough to be useful; the comments should be bilingual in English and Chinese.
4. For everyday use, set appropriate default parameters and make template argument deduction work wherever possible.
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-prompt&quot;&gt;Let us narrow the scope for a moment and fix bugs:
[compiler log ...]
This update should focus on the following points:
1. Introduce finer-grained exception guarantees at the level of `noexcept(move)`.
2. Provide a `small_buffer` optimization (SBO) version.
3. Strengthen feasible static-reflection-style optimization for fundamental types and small types with tractable alignment requirements.
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-prompt&quot;&gt;Keeping the design requirements unchanged (that is, preserving the existing semantic constraints), continue fixing the bugs:
[compiler log ...]
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-prompt&quot;&gt;The current result is already rather substantial.
Next task: generate test code that exercises our stack in a near-saturating fashion; write everything inside the `main` function.
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-prompt&quot;&gt;The test code still contains a problem. Please fix the bug:
[compiler log ...]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2025 azureveil &amp;#x3C;azureveil4295@yeah.net&gt;
//
// This file is part of azureveil stack demo.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see &amp;#x3C;https://www.gnu.org/licenses/&gt;.

#include &amp;#x3C;variant&gt;
#include &amp;#x3C;memory&gt;
#include &amp;#x3C;memory_resource&gt;
#include &amp;#x3C;type_traits&gt;
#include &amp;#x3C;concepts&gt;
#include &amp;#x3C;iterator&gt;
#include &amp;#x3C;utility&gt;
#include &amp;#x3C;new&gt;
#include &amp;#x3C;cstddef&gt;
#include &amp;#x3C;stdexcept&gt;
#include &amp;#x3C;algorithm&gt;
#include &amp;#x3C;initializer_list&gt;
#include &amp;#x3C;array&gt;
#include &amp;#x3C;cstring&gt; // memcpy
#include &amp;#x3C;cassert&gt;

namespace tools
{
    /**
     * @brief A type-list for meta programming. / 用于元编程的类型列表
     */
    template &amp;#x3C;class... Ts&gt;
    struct type_list
    {
    };

    /* ========================= Concepts（概念）========================= */

    /**
     * @brief Check T is in pack Ts...  / 判断类型 T 是否在 Ts... 中
     */
    template &amp;#x3C;class T, class... Ts&gt;
    concept InPack = (std::same_as&amp;#x3C;std::remove_cvref_t&amp;#x3C;T&gt;, Ts&gt; or ...);

    /**
     * @brief Element pack requirements for stack. / 栈的候选类型包需求
     * - every type is destructible and move-constructible
     * - pack size &gt; 0
     *
     * 重要：折叠表达式必须写成 ((A and B) and ...)，避免编译器报
     * &quot;binary expression in operand of fold-expression&quot;。
     */
    template &amp;#x3C;class... Ts&gt;
    concept StackElementPack =
        ((std::destructible&amp;#x3C;Ts&gt; and std::move_constructible&amp;#x3C;Ts&gt;) and ...) and (sizeof...(Ts) &gt; 0);

    /**
     * @brief Allocator can be rebound to T. / 分配器可重绑定到 T
     */
    template &amp;#x3C;class Alloc, class T&gt;
    concept RebindableAllocator = requires {
        typename std::allocator_traits&amp;#x3C;Alloc&gt;::template rebind_alloc&amp;#x3C;T&gt;;
    };

    /**
     * @brief f is a valid visitor for std::variant&amp;#x3C;Ts...&gt;. / 访问器概念
     */
    template &amp;#x3C;class F, class... Ts&gt;
    concept VariantVisitor =
        requires(F f, std::variant&amp;#x3C;Ts...&gt; &amp;#x26;v) { std::visit(f, v); } and
        requires(F f, const std::variant&amp;#x3C;Ts...&gt; &amp;#x26;cv) { std::visit(f, cv); };

    /* ========================= meta: unique types ===================== */

    namespace detail
    {

        /**
         * @brief contains&amp;#x3C;List, T&gt; -&gt; bool_constant  / 判断 T 是否在 type_list 中
         */
        template &amp;#x3C;class List, class T&gt;
        struct contains;

        template &amp;#x3C;class T&gt;
        struct contains&amp;#x3C;type_list&amp;#x3C;&gt;, T&gt; : std::false_type
        {
        };

        template &amp;#x3C;class Head, class... Tail, class T&gt;
        struct contains&amp;#x3C;type_list&amp;#x3C;Head, Tail...&gt;, T&gt;
            : std::conditional_t&amp;#x3C;std::same_as&amp;#x3C;Head, T&gt;, std::true_type, contains&amp;#x3C;type_list&amp;#x3C;Tail...&gt;, T&gt;&gt;
        {
        };

        /**
         * @brief prepend&amp;#x3C;List, T&gt;  / 在列表前部插入
         */
        template &amp;#x3C;class List, class T&gt;
        struct prepend;

        template &amp;#x3C;class... Ts, class T&gt;
        struct prepend&amp;#x3C;type_list&amp;#x3C;Ts...&gt;, T&gt;
        {
            using type = type_list&amp;#x3C;T, Ts...&gt;;
        };

        /**
         * @brief unique_types&amp;#x3C;Ts...&gt; 去重并保持首次出现顺序 / make unique, keep first-appearance order
         */
        template &amp;#x3C;class... Ts&gt;
        struct unique_types;

        template &amp;#x3C;&gt;
        struct unique_types&amp;#x3C;&gt;
        {
            using type = type_list&amp;#x3C;&gt;;
        };

        template &amp;#x3C;class T, class... Rest&gt;
        struct unique_types&amp;#x3C;T, Rest...&gt;
        {
            using rest = typename unique_types&amp;#x3C;Rest...&gt;::type;
            static constexpr bool in = contains&amp;#x3C;rest, T&gt;::value;
            using type = std::conditional_t&amp;#x3C;in, rest, typename prepend&amp;#x3C;rest, T&gt;::type&gt;;
        };

        /**
         * @brief forward decl: to_basic_stack&amp;#x3C;Alloc, type_list&amp;#x3C;...&gt;&gt;
         * 仅声明，不定义，避免重定义冲突！
         */
        template &amp;#x3C;class Alloc, class List&gt;
        struct to_basic_stack;

    } // namespace detail

    /* ========================= basic_stack with SBO =================== */

    /**
     * @class basic_stack
     * @brief A type-safe, allocator-aware multi-type stack based on std::variant,
     *        with optional Small Buffer Optimization (SBO).
     *        使用 std::variant 的类型安全、分配器友好、可选小对象优化（SBO）的多类型栈。
     *
     * @tparam Allocator  allocator type (defaults to std::allocator&amp;#x3C;std::byte&gt;)
     *                    分配器类型（默认 std::allocator&amp;#x3C;std::byte&gt;）
     * @tparam SBO        inline capacity in elements for small-buffer optimization
     *                    小对象优化的内联容量（按元素个数）
     * @tparam Types...   element alternative types (non-empty pack)
     *                    备选元素类型（非空包）
     *
     * # Design highlights / 设计要点
     * - Storage is `std::variant&amp;#x3C;Types...&gt;` for type-safety &amp;#x26; alignment.（对齐与类型安全由 variant 保证）
     * - Manual lifetime with `std::construct_at` / `std::destroy_at`.（手动控制对象生命周期）
     * - Standard-style iterators (contiguous).（标准库风格迭代器，连续存储）
     * - Supports PMR 和常规分配器。/ Supports PMR and regular allocators.
     * - `noexcept(move)` granular policy: relocation chooses move-or-copy by traits. /
     *    基于类型性质（traits）选择“移动或拷贝”，提供细粒度异常保证。
     * - SBO: small sizes live on-stack; larger spill to heap. / 小容量走栈上内联，大容量溢出到堆。
     *
     * @note 对“静态反射（static reflection）”的可行优化：
     *  - 若 `storage_type`（即 `std::variant&amp;#x3C;Ts...&gt;`）满足
     *    `std::is_trivially_copyable_v`，则迁移使用 `memcpy` 快路径；
     *  - 否则若 `std::is_nothrow_move_constructible_v&amp;#x3C;storage_type&gt;`，则采用移动构造；
     *  - 否则退化为拷贝构造，保持强异常保证（strong exception safety）。
     */
    template &amp;#x3C;
        class Allocator = std::allocator&amp;#x3C;std::byte&gt;,
        std::size_t SBO = 0,
        class... Types&gt;
        requires StackElementPack&amp;#x3C;Types...&gt; and RebindableAllocator&amp;#x3C;Allocator, std::variant&amp;#x3C;Types...&gt;&gt;
    class basic_stack
    {
    public:
        using storage_type = std::variant&amp;#x3C;Types...&gt;;
        using value_type = storage_type;
        using allocator_type = typename std::allocator_traits&amp;#x3C;Allocator&gt;::template rebind_alloc&amp;#x3C;storage_type&gt;;
        using allocator_traits = std::allocator_traits&amp;#x3C;allocator_type&gt;;

        using size_type = std::size_t;
        using difference_type = std::ptrdiff_t;

        using reference = storage_type &amp;#x26;;
        using const_reference = const storage_type &amp;#x26;;
        using pointer = storage_type *;
        using const_pointer = const storage_type *;

        using iterator = storage_type *;
        using const_iterator = const storage_type *;
        using reverse_iterator = std::reverse_iterator&amp;#x3C;iterator&gt;;
        using const_reverse_iterator = std::reverse_iterator&amp;#x3C;const_iterator&gt;;

    private:
        // ---- Static reflection knobs / 静态性质开关 ----
        static constexpr bool triv_copyable = std::is_trivially_copyable_v&amp;#x3C;storage_type&gt;;
        static constexpr bool triv_destruct = std::is_trivially_destructible_v&amp;#x3C;storage_type&gt;;
        static constexpr bool nothrow_move = std::is_nothrow_move_constructible_v&amp;#x3C;storage_type&gt;;
        static constexpr std::size_t TSize = sizeof(storage_type);
        static constexpr std::size_t TAlign = alignof(storage_type);
        static constexpr bool has_sbo = (SBO &gt; 0);

        /// @brief SBO 内联块（仅在 has_sbo 为真时作为候选）/ inline storage when SBO enabled
        struct alignas(TAlign) sbo_block
        {
            std::array&amp;#x3C;std::byte, SBO * TSize&gt; buf{};
        };

        /// @brief 无 SBO 时的占位类型（空壳）/ empty placeholder when SBO disabled
        struct no_sbo_block
        {
        };

        /// @brief 依据 has_sbo 选择实际的 sbo_ 成员类型
        using sbo_storage_t = std::conditional_t&amp;#x3C;has_sbo, sbo_block, no_sbo_block&gt;;

    public:
        /* ------------- constructors / 构造与析构 ------------- */

        /**
         * @brief Default ctor (uses SBO if available, otherwise no allocation).
         *        默认构造（若启用 SBO 则指向内联缓冲，否则不分配）
         */
        basic_stack() noexcept(noexcept(allocator_type{}))
            : alloc_{}, data_{init_data_ptr_()}, size_{0}, cap_{init_cap_()} {}

        /**
         * @brief Construct with allocator. / 指定分配器构造
         */
        explicit basic_stack(const Allocator &amp;#x26;a)
            : alloc_{rebind_alloc_(a)}, data_{init_data_ptr_()}, size_{0}, cap_{init_cap_()} {}

        /**
         * @brief PMR resource ctor (enabled only for PMR allocator). /
         *        PMR 资源构造（仅当分配器为 PMR 时启用）
         */
        basic_stack(std::pmr::memory_resource *r)
            requires std::same_as&amp;#x3C;std::remove_cvref_t&amp;#x3C;Allocator&gt;, std::pmr::polymorphic_allocator&amp;#x3C;std::byte&gt;&gt;
            : alloc_{allocator_type{r}}, data_{init_data_ptr_()}, size_{0}, cap_{init_cap_()}
        {
        }

        /**
         * @brief Reserve capacity upfront. / 预留容量的构造
         * @param reserve_cap initial capacity / 初始容量
         * @param a allocator (optional) / 可选分配器
         */
        explicit basic_stack(size_type reserve_cap, const Allocator &amp;#x26;a = Allocator{})
            : alloc_{rebind_alloc_(a)}, data_{init_data_ptr_()}, size_{0}, cap_{init_cap_()}
        {
            if (reserve_cap &gt; cap_)
                reserve(reserve_cap);
        }

        /**
         * @brief Construct from initializer_list of variants. / 从 variant 列表构造
         */
        basic_stack(std::initializer_list&amp;#x3C;storage_type&gt; init, const Allocator &amp;#x26;a = Allocator{})
            : alloc_{rebind_alloc_(a)}, data_{init_data_ptr_()}, size_{0}, cap_{init_cap_()}
        {
            reserve(init.size());
            for (auto const &amp;#x26;v : init)
                push(v);
        }

        basic_stack(const basic_stack &amp;#x26;other)
            : alloc_{allocator_traits::select_on_container_copy_construction(other.alloc_)}, data_{init_data_ptr_()}, size_{0}, cap_{init_cap_()}
        {
            reserve(other.size_);
            try
            {
                uninit_copy_n_(other.data_, other.size_, data_);
                size_ = other.size_;
            }
            catch (...)
            {
                destroy_n_(data_, size_);
                deallocate_if_heap_();
                throw;
            }
        }

        basic_stack(basic_stack &amp;#x26;&amp;#x26;other) noexcept
            : alloc_{std::move(other.alloc_)}, data_{init_data_ptr_()}, size_{0}, cap_{init_cap_()}
        {
            // 优先：若分配器“总是相等”，可直接窃取缓冲
            if constexpr (allocator_traits::is_always_equal::value)
            {
                if (other.using_heap_())
                {
                    data_ = other.data_;
                    cap_ = other.cap_;
                    size_ = other.size_;
                    other.data_ = other.inline_ptr_();
                    other.cap_ = other.init_cap_();
                    other.size_ = 0;
                    return;
                }
            }
            // PMR 特例：同一 resource 也可安全窃取
            else if constexpr (std::same_as&amp;#x3C;std::remove_cvref_t&amp;#x3C;Allocator&gt;, std::pmr::polymorphic_allocator&amp;#x3C;std::byte&gt;&gt;)
            {
                if (other.using_heap_() and alloc_.resource() == other.alloc_.resource())
                {
                    data_ = other.data_;
                    cap_ = other.cap_;
                    size_ = other.size_;
                    other.data_ = other.inline_ptr_();
                    other.cap_ = other.init_cap_();
                    other.size_ = 0;
                    return;
                }
            }
        }

        basic_stack &amp;#x26;operator=(const basic_stack &amp;#x26;other)
        {
            if (this == &amp;#x26;other)
                return *this;
            if constexpr (allocator_traits::propagate_on_container_copy_assignment::value)
            {
                if (alloc_ != other.alloc_)
                {
                    clear();
                    deallocate_if_heap_();
                }
                alloc_ = other.alloc_;
            }
            if (other.size_ &gt; cap_)
            {
                reallocate_to_(other.size_);
            }
            // 赋值已有元素并填充/销毁多余
            const size_type common = std::min(size_, other.size_);
            for (size_type i = 0; i &amp;#x3C; common; ++i)
                data_[i] = other.data_[i];
            if (size_ &amp;#x3C; other.size_)
            {
                uninit_copy_n_(other.data_ + size_, other.size_ - size_, data_ + size_);
            }
            else
            {
                destroy_n_(data_ + other.size_, size_ - other.size_);
            }
            size_ = other.size_;
            return *this;
        }

        basic_stack &amp;#x26;operator=(basic_stack &amp;#x26;&amp;#x26;other) noexcept(
            allocator_traits::propagate_on_container_move_assignment::value or
            std::is_nothrow_move_assignable_v&amp;#x3C;allocator_type&gt;)
        {
            if (this == &amp;#x26;other)
                return *this;
            if constexpr (allocator_traits::propagate_on_container_move_assignment::value)
            {
                clear();
                deallocate_if_heap_();
                alloc_ = std::move(other.alloc_);
                if (other.using_heap_())
                {
                    data_ = other.data_;
                    size_ = other.size_;
                    cap_ = other.cap_;
                    other.data_ = other.inline_ptr_();
                    other.size_ = 0;
                    other.cap_ = other.init_cap_();
                }
                else
                {
                    data_ = inline_ptr_();
                    cap_ = init_cap_();
                    size_ = 0;
                    reserve(other.size_);
                    uninit_move_or_copy_n_(other.data_, other.size_, data_);
                    size_ = other.size_;
                    other.clear();
                }
            }
            else
            {
                if (alloc_ == other.alloc_)
                {
                    clear();
                    deallocate_if_heap_();
                    if (other.using_heap_())
                    {
                        data_ = other.data_;
                        size_ = other.size_;
                        cap_ = other.cap_;
                        other.data_ = other.inline_ptr_();
                        other.size_ = 0;
                        other.cap_ = other.init_cap_();
                    }
                    else
                    {
                        data_ = inline_ptr_();
                        cap_ = init_cap_();
                        size_ = 0;
                        reserve(other.size_);
                        uninit_move_or_copy_n_(other.data_, other.size_, data_);
                        size_ = other.size_;
                        other.clear();
                    }
                }
                else
                {
                    assign_move_from_(other);
                }
            }
            return *this;
        }

        ~basic_stack()
        {
            destroy_n_(data_, size_);
            deallocate_if_heap_();
        }

        /* ------------- iterators / 迭代器 ------------- */

        /// @brief begin / 起始迭代器
        iterator begin() noexcept { return data_; }
        const_iterator begin() const noexcept { return data_; }
        const_iterator cbegin() const noexcept { return data_; }

        /// @brief end / 末尾迭代器
        iterator end() noexcept { return data_ + size_; }
        const_iterator end() const noexcept { return data_ + size_; }
        const_iterator cend() const noexcept { return data_ + size_; }

        /// @brief reverse begin / 反向起始
        reverse_iterator rbegin() noexcept { return reverse_iterator{end()}; }
        const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator{end()}; }
        const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator{end()}; }

        /// @brief reverse end / 反向末尾
        reverse_iterator rend() noexcept { return reverse_iterator{begin()}; }
        const_reverse_iterator rend() const noexcept { return const_reverse_iterator{begin()}; }
        const_reverse_iterator crend() const noexcept { return const_reverse_iterator{begin()}; }

        /* ------------- capacity / 容量 ------------- */

        /// @brief empty? / 是否为空
        [[nodiscard]] bool empty() const noexcept { return size_ == 0; }

        /// @brief size / 当前大小
        [[nodiscard]] size_type size() const noexcept { return size_; }

        /// @brief capacity / 当前容量
        [[nodiscard]] size_type capacity() const noexcept { return cap_; }

        /// @brief reserve capacity / 预留容量
        void reserve(size_type new_cap)
        {
            if (new_cap &amp;#x3C;= cap_)
                return;
            reallocate_to_(new_cap);
        }

        /// @brief shrink to fit (may move back into SBO) / 收缩容量（可能回迁至 SBO）
        void shrink_to_fit()
        {
            if (size_ == cap_)
                return;
            const size_type target = size_;
            // 若启用 SBO 且可容纳，则回迁内联
            if constexpr (has_sbo)
            {
                if (target &amp;#x3C;= SBO)
                {
                    reallocate_to_(SBO);
                    return;
                }
            }
            reallocate_to_(target);
        }

        /// @brief clear (destroy all elements) / 清空（析构所有元素）
        void clear() noexcept
        {
            destroy_n_(data_, size_);
            size_ = 0;
        }

        /* ------------- element access / 访问 ------------- */

        /// @brief top (mutable) / 顶部元素（可变）
        reference top()
        {
            if (empty())
                throw std::out_of_range(&quot;stack is empty&quot;);
            return data_[size_ - 1];
        }
        /// @brief top (const) / 顶部元素（常量）
        const_reference top() const
        {
            if (empty())
                throw std::out_of_range(&quot;stack is empty&quot;);
            return data_[size_ - 1];
        }

        /**
         * @brief Visit top via visitor. / 使用访问器访问顶部元素
         */
        template &amp;#x3C;VariantVisitor&amp;#x3C;Types...&gt; F&gt;
        decltype(auto) visit_top(F &amp;#x26;&amp;#x26;f)
        {
            return std::visit(std::forward&amp;#x3C;F&gt;(f), top());
        }
        template &amp;#x3C;VariantVisitor&amp;#x3C;Types...&gt; F&gt;
        decltype(auto) visit_top(F &amp;#x26;&amp;#x26;f) const
        {
            return std::visit(std::forward&amp;#x3C;F&gt;(f), top());
        }

        /**
         * @brief Visit all elements. / 访问所有元素
         */
        template &amp;#x3C;VariantVisitor&amp;#x3C;Types...&gt; F&gt;
        void visit_all(F &amp;#x26;&amp;#x26;f)
        {
            for (auto &amp;#x26;e : *this)
                std::visit(f, e);
        }
        template &amp;#x3C;VariantVisitor&amp;#x3C;Types...&gt; F&gt;
        void visit_all(F &amp;#x26;&amp;#x26;f) const
        {
            for (auto &amp;#x26;e : *this)
                std::visit(f, e);
        }

        /* ------------- modifiers / 修改器 ------------- */

        /**
         * @brief Push a variant value. / 压入一个 variant 值
         */
        void push(value_type v)
        {
            ensure_growth_();
            std::construct_at(data_ + size_, std::move(v));
            ++size_;
        }

        /**
         * @brief Push a concrete alternative in Types... / 压入具体候选类型的值
         */
        template &amp;#x3C;class T&gt;
            requires InPack&amp;#x3C;T, Types...&gt;
        void push(T &amp;#x26;&amp;#x26;x)
        {
            ensure_growth_();
            std::construct_at(
                data_ + size_,
                std::in_place_type&amp;#x3C;std::remove_cvref_t&amp;#x3C;T&gt;&gt;,
                std::forward&amp;#x3C;T&gt;(x));
            ++size_;
        }

        /**
         * @brief Emplace the top element as alternative T. / 原地构造指定候选类型 T 的顶部元素
         */
        template &amp;#x3C;class T, class... Args&gt;
            requires InPack&amp;#x3C;T, Types...&gt; and std::constructible_from&amp;#x3C;T, Args...&gt;
        reference emplace(Args &amp;#x26;&amp;#x26;...args)
        {
            ensure_growth_();
            std::construct_at(data_ + size_, std::in_place_type&amp;#x3C;T&gt;, std::forward&amp;#x3C;Args&gt;(args)...);
            ++size_;
            return data_[size_ - 1];
        }

        /**
         * @brief Pop the top element (destroy). / 弹出顶部元素（析构）
         */
        void pop()
        {
            if (empty())
                throw std::out_of_range(&quot;stack is empty&quot;);
            std::destroy_at(data_ + (size_ - 1));
            --size_;
        }

        /* ------------- allocator / 分配器 ------------- */

        /// @brief get allocator / 获取分配器
        allocator_type get_allocator() const noexcept { return alloc_; }

        /**
         * @brief Rebind to another allocator type. / 迁移到另一种分配器策略
         * @note Copy/move variant elements as needed. / 根据异常安全选择拷贝或移动
         */
        template &amp;#x3C;class NewAlloc&gt;
            requires RebindableAllocator&amp;#x3C;NewAlloc, storage_type&gt;
        basic_stack&amp;#x3C;NewAlloc, SBO, Types...&gt; rebind_allocator(const NewAlloc &amp;#x26;na = NewAlloc{}) const
        {
            basic_stack&amp;#x3C;NewAlloc, SBO, Types...&gt; dst(na);
            dst.reserve(size_);
            for (size_type i = 0; i &amp;#x3C; size_; ++i)
            {
                dst.push(data_[i]);
            }
            return dst;
        }

    private:
        /* ------------- internal helpers / 内部工具 ------------- */

        // —— SBO helpers / SBO 辅助 —— //
        pointer inline_ptr_() noexcept
        {
            if constexpr (has_sbo)
            {
                // std::launder: 避免潜在的严格别名与生命周期问题
                return std::launder(reinterpret_cast&amp;#x3C;pointer&gt;(sbo_.buf.data()));
            }
            else
            {
                return nullptr;
            }
        }
        const_pointer inline_ptr_() const noexcept
        {
            if constexpr (has_sbo)
            {
                return std::launder(reinterpret_cast&amp;#x3C;const_pointer&gt;(sbo_.buf.data()));
            }
            else
            {
                return nullptr;
            }
        }
        bool using_heap_() const noexcept
        {
            if constexpr (has_sbo)
                return data_ != inline_ptr_();
            else
                return data_ != nullptr;
        }
        pointer init_data_ptr_() noexcept
        {
            if constexpr (has_sbo)
                return inline_ptr_();
            else
                return nullptr;
        }
        size_type init_cap_() const noexcept
        {
            if constexpr (has_sbo)
                return SBO;
            else
                return 0;
        }

        static allocator_type rebind_alloc_(const Allocator &amp;#x26;a)
        {
            using rebound = typename std::allocator_traits&amp;#x3C;Allocator&gt;::template rebind_alloc&amp;#x3C;storage_type&gt;;
            return rebound{a};
        }

        pointer allocate_(size_type n) { return allocator_traits::allocate(alloc_, n); }

        void deallocate_if_heap_() noexcept
        {
            if (using_heap_() and data_)
                allocator_traits::deallocate(alloc_, data_, cap_);
            data_ = init_data_ptr_();
            cap_ = init_cap_();
        }

        static void destroy_n_(pointer p, size_type n) noexcept
        {
            for (size_type i = 0; i &amp;#x3C; n; ++i)
            {
                std::destroy_at(p + i);
            }
        }

        static void uninit_copy_n_(const_pointer src, size_type n, pointer dst)
        {
            size_type i = 0;
            try
            {
                for (; i &amp;#x3C; n; ++i)
                    std::construct_at(dst + i, src[i]);
            }
            catch (...)
            {
                destroy_n_(dst, i);
                throw;
            }
        }

        // —— granular move/copy by traits / 基于性质的精细迁移 —— //
        static void uninit_move_or_copy_n_(pointer src, size_type n, pointer dst)
        {
            // Fast path: trivially copyable → memcpy
            if constexpr (triv_copyable)
            {
                std::memcpy(static_cast&amp;#x3C;void *&gt;(dst), static_cast&amp;#x3C;void const *&gt;(src), n * TSize);
                return;
            }
            size_type i = 0;
            try
            {
                if constexpr (nothrow_move)
                {
                    for (; i &amp;#x3C; n; ++i)
                        std::construct_at(dst + i, std::move(src[i]));
                }
                else
                {
                    for (; i &amp;#x3C; n; ++i)
                        std::construct_at(dst + i, src[i]); // fallback copy
                }
            }
            catch (...)
            {
                destroy_n_(dst, i);
                throw;
            }
        }

        void reallocate_to_(size_type new_cap)
        {
            // 选择目标缓冲区：优先使用 SBO（若可容纳）
            pointer new_buf = nullptr;
            if constexpr (has_sbo)
            {
                new_buf = (new_cap &amp;#x3C;= SBO) ? inline_ptr_() : allocate_(new_cap);
            }
            else
            {
                new_buf = allocate_(new_cap);
            }

            if (new_buf == data_)
            { // 仍在同一缓冲，无需动作
                cap_ = (new_buf == inline_ptr_()) ? init_cap_() : new_cap;
                return;
            }

            size_type moved = 0;
            try
            {
                uninit_move_or_copy_n_(data_, size_, new_buf);
                moved = size_;
            }
            catch (...)
            {
                if (new_buf != inline_ptr_())
                {
                    destroy_n_(new_buf, moved); // 对于 memcpy 情况，trivial dtor 则无副作用
                    allocator_traits::deallocate(alloc_, new_buf, new_cap);
                }
                throw;
            }
            // 旧缓冲区清理
            destroy_n_(data_, size_);
            if (using_heap_())
                allocator_traits::deallocate(alloc_, data_, cap_);

            data_ = new_buf;
            cap_ = (data_ == inline_ptr_()) ? init_cap_() : new_cap;
        }

        void ensure_growth_()
        {
            if (size_ == cap_)
            {
                const size_type base = (cap_ == 0) ? (has_sbo ? SBO : 0) : cap_;
                const size_type new_cap = (base == 0) ? 4 : (base * 2);
                reallocate_to_(new_cap);
            }
        }

        void assign_move_from_(basic_stack &amp;#x26;other)
        {
            clear();
            reserve(other.size_);
            uninit_move_or_copy_n_(other.data_, other.size_, data_);
            size_ = other.size_;
            other.clear();
        }

    private:
        allocator_type alloc_{};
        pointer data_{nullptr};
        size_type size_{0};
        size_type cap_{0};
        // SBO storage (exists only if SBO&gt;0) / 仅当 SBO&gt;0 才有意义
        sbo_storage_t sbo_{};
    };

    /* ========================= Aliases / 别名 ========================= */

    template &amp;#x3C;class... Types&gt;
    using Stack = basic_stack&amp;#x3C;std::allocator&amp;#x3C;std::byte&gt;, 0, Types...&gt;;

    template &amp;#x3C;std::size_t SBO, class... Types&gt;
    using SmallStack = basic_stack&amp;#x3C;std::allocator&amp;#x3C;std::byte&gt;, SBO, Types...&gt;;

    template &amp;#x3C;class... Types&gt;
    using PmrStack = basic_stack&amp;#x3C;std::pmr::polymorphic_allocator&amp;#x3C;std::byte&gt;, 0, Types...&gt;;

    template &amp;#x3C;std::size_t SBO, class... Types&gt;
    using PmrSmallStack = basic_stack&amp;#x3C;std::pmr::polymorphic_allocator&amp;#x3C;std::byte&gt;, SBO, Types...&gt;;

    /* === meta glue: materialize to_basic_stack (after basic_stack exists) === */
    /* ！！！修复重定义：只在此处做唯一的偏特化定义，之前仅声明不定义。 */

    namespace detail
    {
        template &amp;#x3C;class Alloc, class... Ts&gt;
        struct to_basic_stack&amp;#x3C;Alloc, type_list&amp;#x3C;Ts...&gt;&gt;
        {
            using type = basic_stack&amp;#x3C;Alloc, 0, Ts...&gt;;
        };
    } // namespace detail

    /* ========================= Factory helpers / 工厂辅助 ==================== */
    /**
     * @brief Make a stack with deduced unique types from arguments (default allocator).
     *        通过实参类型推导并去重，构造使用默认分配器的栈。
     *
     * @return stack with Types... = unique(remove_cvref_t&amp;#x3C;Args&gt;...)  / 去重后的类型包
     *
     * 使用示例：
     *   auto s = tools::stack_of(1, std::string{&quot;x&quot;}, 3.14); // Stack&amp;#x3C;int, std::string, double&gt;
     */
    template &amp;#x3C;class... Args&gt;
    auto stack_of(Args &amp;#x26;&amp;#x26;...)
    {
        using uniq_list = typename detail::unique_types&amp;#x3C;std::remove_cvref_t&amp;#x3C;Args&gt;...&gt;::type;
        using stack_t = typename detail::to_basic_stack&amp;#x3C;std::allocator&amp;#x3C;std::byte&gt;, uniq_list&gt;::type;
        return stack_t{};
    }

    /**
     * @brief Make a stack with a given allocator. / 使用给定分配器的工厂
     */
    template &amp;#x3C;class Alloc, class... Args&gt;
        requires RebindableAllocator&amp;#x3C;Alloc, std::variant&amp;#x3C;std::remove_cvref_t&amp;#x3C;Args&gt;...&gt;&gt;
    auto stack_of_with_alloc(const Alloc &amp;#x26;a, Args &amp;#x26;&amp;#x26;...)
    {
        using uniq_list = typename detail::unique_types&amp;#x3C;std::remove_cvref_t&amp;#x3C;Args&gt;...&gt;::type;
        using stack_t = typename detail::to_basic_stack&amp;#x3C;Alloc, uniq_list&gt;::type;
        return stack_t{a};
    }

    /**
     * @brief PMR convenience factory. / PMR 快捷工厂
     */
    template &amp;#x3C;class... Args&gt;
    auto stack_of_pmr(std::pmr::memory_resource *r, Args &amp;#x26;&amp;#x26;...)
    {
        using uniq_list = typename detail::unique_types&amp;#x3C;std::remove_cvref_t&amp;#x3C;Args&gt;...&gt;::type;
        using stack_t = typename detail::to_basic_stack&amp;#x3C;std::pmr::polymorphic_allocator&amp;#x3C;std::byte&gt;, uniq_list&gt;::type;
        return stack_t{r};
    }

    /* ========================= CTAD guides / 推导指引 ======================== */
    /**
     * @brief Deduce Ts... from initializer_list&amp;#x3C;variant&amp;#x3C;Ts...&gt;&gt; (default allocator).
     *        从 initializer_list&amp;#x3C;variant&amp;#x3C;Ts...&gt;&gt; 推导元素类型（默认分配器）
     */
    template &amp;#x3C;class... Ts&gt;
    basic_stack(std::initializer_list&amp;#x3C;std::variant&amp;#x3C;Ts...&gt;&gt;, std::allocator&amp;#x3C;std::byte&gt;)
        -&gt; basic_stack&amp;#x3C;std::allocator&amp;#x3C;std::byte&gt;, 0, Ts...&gt;;
    template &amp;#x3C;class... Ts&gt;
    basic_stack(std::initializer_list&amp;#x3C;std::variant&amp;#x3C;Ts...&gt;&gt;)
        -&gt; basic_stack&amp;#x3C;std::allocator&amp;#x3C;std::byte&gt;, 0, Ts...&gt;;

    /**
     * @brief Deduce Ts... + PMR allocator from initializer_list. / 从初始化列表推导 Ts... 与 PMR 分配器
     */
    template &amp;#x3C;class... Ts&gt;
    basic_stack(std::initializer_list&amp;#x3C;std::variant&amp;#x3C;Ts...&gt;&gt;, std::pmr::polymorphic_allocator&amp;#x3C;std::byte&gt;)
        -&gt; basic_stack&amp;#x3C;std::pmr::polymorphic_allocator&amp;#x3C;std::byte&gt;, 0, Ts...&gt;;

} // namespace tools
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2025 azureveil &amp;#x3C;azureveil4295@yeah.net&gt;
//
// This file is part of azureveil stack demo.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see &amp;#x3C;https://www.gnu.org/licenses/&gt;.

#include &quot;stack.hpp&quot;

#include &amp;#x3C;cassert&gt;
#include &amp;#x3C;string&gt;
#include &amp;#x3C;iostream&gt;
#include &amp;#x3C;variant&gt;
#include &amp;#x3C;vector&gt;
#include &amp;#x3C;array&gt;
#include &amp;#x3C;memory_resource&gt;
#include &amp;#x3C;algorithm&gt;
#include &amp;#x3C;stdexcept&gt;
#include &amp;#x3C;cctype&gt;
#include &amp;#x3C;type_traits&gt;
#include &amp;#x3C;climits&gt;

// —— 两个测试类型必须放在函数外：标准禁止局部类含静态数据成员 ——

// 计数型：用于验证生命周期（构造/析构数量）
struct Counted
{
    static int live;
    int id = -1;
    Counted() : id(-1) { ++live; }
    explicit Counted(int i) : id(i) { ++live; }
    Counted(const Counted &amp;#x26;o) : id(o.id) { ++live; }
    Counted(Counted &amp;#x26;&amp;#x26;o) noexcept : id(o.id) { ++live; }
    Counted &amp;#x26;operator=(const Counted &amp;#x26;) = default;
    Counted &amp;#x26;operator=(Counted &amp;#x26;&amp;#x26;) = default;
    ~Counted() { --live; }
};
int Counted::live = 0;

// 用于异常路径：拷贝到第 N 次时抛异常；移动构造非 noexcept，促使“回退拷贝路径”
struct ThrowOnCopy
{
    static int copy_count;
    static int throw_after;
    int v = 0;
    ThrowOnCopy() = default;
    explicit ThrowOnCopy(int x) : v(x) {}
    ThrowOnCopy(const ThrowOnCopy &amp;#x26;o) : v(o.v)
    {
        if (++copy_count == throw_after)
            throw std::runtime_error(&quot;copy boom&quot;);
    }
    ThrowOnCopy(ThrowOnCopy &amp;#x26;&amp;#x26;o) noexcept(false) : v(o.v) {}
    ThrowOnCopy &amp;#x26;operator=(const ThrowOnCopy &amp;#x26;) = default;
    ThrowOnCopy &amp;#x26;operator=(ThrowOnCopy &amp;#x26;&amp;#x26;) = default;
    ~ThrowOnCopy() = default;
};
int ThrowOnCopy::copy_count = 0;
int ThrowOnCopy::throw_after = INT_MAX;

int main()
{
    using namespace tools;

    // ========== 1) 基础功能：SmallStack + 多类型 push/emplace/visit ==========
    {
        SmallStack&amp;#x3C;4, int, std::string, double, Counted&gt; s; // SBO=4
        assert(s.empty());
        s.emplace&amp;#x3C;int&gt;(42);
        s.push(std::string{&quot;alpha&quot;});
        s.push(3.14);
        s.emplace&amp;#x3C;Counted&gt;(7);

        assert(s.size() == 4);
        assert(s.capacity() &gt;= 4);
        s.visit_top([](auto const &amp;#x26;x)
                    {
            using T = std::decay_t&amp;#x3C;decltype(x)&gt;;
            if constexpr (std::is_same_v&amp;#x3C;T, Counted&gt;) assert(x.id == 7); });

        int cnt_int = 0;
        int cnt_str = 0;
        int cnt_dbl = 0;
        int cnt_cnt = 0;
        long long sum_int = 0;
        double sum_dbl = 0.0;
        s.visit_all([&amp;#x26;](auto const &amp;#x26;x)
                    {
            using T = std::decay_t&amp;#x3C;decltype(x)&gt;;
            if constexpr (std::is_same_v&amp;#x3C;T, int&gt;) { ++cnt_int; sum_int += x; }
            else if constexpr (std::is_same_v&amp;#x3C;T, std::string&gt;) { ++cnt_str; }
            else if constexpr (std::is_same_v&amp;#x3C;T, double&gt;) { ++cnt_dbl; sum_dbl += x; }
            else if constexpr (std::is_same_v&amp;#x3C;T, Counted&gt;) { ++cnt_cnt; } });
        assert(cnt_int == 1 and cnt_str == 1 and cnt_dbl == 1 and cnt_cnt == 1);
        assert(sum_int == 42);
        assert(sum_dbl &gt; 3.0 and sum_dbl &amp;#x3C; 3.2);

        int live_before = Counted::live;
        s.pop(); // 弹出 Counted{7}
        assert(Counted::live == live_before - 1);
        assert(s.size() == 3);
        s.clear();
        assert(s.empty());
    }

    // ========== 2) 容量行为：SBO 命中、溢出堆、shrink 回迁 ==========
    {
        SmallStack&amp;#x3C;4, int, std::string&gt; s;
        for (int i = 0; i &amp;#x3C; 4; ++i)
            s.push(i); // SBO 内
        assert(s.capacity() == 4);

        s.push(100); // 触发溢出
        assert(s.capacity() &gt;= 5);

        while (s.size() &gt; 4)
            s.pop(); // 回到 SBO 大小
        s.shrink_to_fit();
        assert(s.capacity() == 4); // 回迁成功
    }

    // ========== 3) reserve/growth：多次重分配不丢数据 ==========
    {
        Stack&amp;#x3C;int, std::string&gt; s;
        for (int i = 0; i &amp;#x3C; 100; ++i)
        {
            if (i % 10 == 0)
                s.push(std::string{&quot;s-&quot; + std::to_string(i)});
            else
                s.push(i);
        }
        int ints = 0, strs = 0, sum = 0;
        s.visit_all([&amp;#x26;](auto const &amp;#x26;x)
                    {
            using T = std::decay_t&amp;#x3C;decltype(x)&gt;;
            if constexpr (std::is_same_v&amp;#x3C;T, int&gt;) { ++ints; sum += x; }
            else if constexpr (std::is_same_v&amp;#x3C;T, std::string&gt;) { ++strs; } });
        assert(ints == 90 and strs == 10);
        assert(s.size() == 100);
        const auto sz = s.size();
        s.shrink_to_fit();
        assert(s.size() == sz);
    }

    // ========== 4) PMR：单调缓冲资源 + PmrSmallStack ==========
    {
        std::array&amp;#x3C;std::byte, 4096&gt; buf{};
        std::pmr::monotonic_buffer_resource mbr(buf.data(), buf.size());
        PmrSmallStack&amp;#x3C;4, int, std::string&gt; ps(&amp;#x26;mbr);
        ps.emplace&amp;#x3C;int&gt;(1);
        ps.emplace&amp;#x3C;std::string&gt;(&quot;pmr&quot;);
        ps.emplace&amp;#x3C;int&gt;(2);
        ps.emplace&amp;#x3C;int&gt;(3); // 填满 SBO
        ps.emplace&amp;#x3C;int&gt;(4); // 溢出到堆（仍由 mbr 管）
        assert(ps.size() == 5);
        int sum = 0, strings = 0;
        ps.visit_all([&amp;#x26;](auto const &amp;#x26;x)
                     {
            using T = std::decay_t&amp;#x3C;decltype(x)&gt;;
            if constexpr (std::is_same_v&amp;#x3C;T, int&gt;) sum += x;
            else if constexpr (std::is_same_v&amp;#x3C;T, std::string&gt;) ++strings; });
        assert(sum == (1 + 2 + 3 + 4) and strings == 1);
    }

    // ========== 5) 工厂函数与 CTAD（不再用严格顺序的 static_assert） ==========
    {
        auto s1 = stack_of(1, std::string{&quot;x&quot;}, 2.5, 3, 4.0);
        using stor1 = typename decltype(s1)::storage_type;
        static_assert(std::variant_size_v&amp;#x3C;stor1&gt; == 3);
        // 运行期验证三种类型都能正常压入/访问
        s1.push(123);
        s1.push(std::string{&quot;ok&quot;});
        s1.push(3.14);
        bool saw_int = false, saw_str = false, saw_dbl = false;
        s1.visit_all([&amp;#x26;](auto const &amp;#x26;x)
                     {
            using T = std::decay_t&amp;#x3C;decltype(x)&gt;;
            if constexpr (std::is_same_v&amp;#x3C;T,int&gt;) saw_int = true;
            if constexpr (std::is_same_v&amp;#x3C;T,std::string&gt;) saw_str = true;
            if constexpr (std::is_same_v&amp;#x3C;T,double&gt;) saw_dbl = true; });
        assert(saw_int and saw_str and saw_dbl);

        // PMR 工厂 &amp;#x26; initializer_list + CTAD
        std::pmr::monotonic_buffer_resource mbr;
        auto s2 = stack_of_pmr(&amp;#x26;mbr, 1, std::string{&quot;y&quot;}, 3.0);
        using stor2 = typename decltype(s2)::storage_type;
        static_assert(std::variant_size_v&amp;#x3C;stor2&gt; == 3);

        using V = std::variant&amp;#x3C;int, std::string&gt;;
        basic_stack lst = {V{1}, V{std::string{&quot;ctad&quot;}}}; // Ts... 推导为 &amp;#x3C;int, std::string&gt;
        assert(lst.size() == 2);
    }

    // ========== 6) rebind_allocator：迁移到 PMR ==========
    {
        auto s = stack_of(1, std::string{&quot;reb&quot;}, 2.0);
        s.push(7);
        s.push(std::string{&quot;z&quot;});
        std::array&amp;#x3C;std::byte, 2048&gt; buf{};
        std::pmr::monotonic_buffer_resource mbr(buf.data(), buf.size());
        auto sp = s.rebind_allocator(std::pmr::polymorphic_allocator&amp;#x3C;std::byte&gt;{&amp;#x26;mbr});
        assert(sp.size() == s.size());

        auto stringify = [](auto const &amp;#x26;v) -&gt; std::string
        {
            return std::visit([](auto const &amp;#x26;x) -&gt; std::string
                              {
                using T = std::decay_t&amp;#x3C;decltype(x)&gt;;
                if constexpr (std::is_same_v&amp;#x3C;T, std::string&gt;) return x;
                else return std::to_string(x); }, v);
        };

        std::vector&amp;#x3C;std::string&gt; a, b;
        a.reserve(s.size());
        b.reserve(sp.size());
        for (auto const &amp;#x26;e : s)
            a.push_back(stringify(e));
        for (auto const &amp;#x26;e : sp)
            b.push_back(stringify(e));
        assert(a == b);
    }

    // ========== 7) 变更访问：就地变换字符串 ==========
    {
        SmallStack&amp;#x3C;4, int, std::string&gt; s;
        s.push(1);
        s.push(std::string{&quot;MiXed&quot;});
        s.push(2);
        for (auto &amp;#x26;v : s)
        {
            std::visit([](auto &amp;#x26;x)
                       {
                using T = std::decay_t&amp;#x3C;decltype(x)&gt;;
                if constexpr (std::is_same_v&amp;#x3C;T, std::string&gt;) {
                    for (auto&amp;#x26; c : x) c = static_cast&amp;#x3C;char&gt;(std::toupper(static_cast&amp;#x3C;unsigned char&gt;(c)));
                } }, v);
        }
        bool seen_upper = false;
        s.visit_all([&amp;#x26;](auto const &amp;#x26;x)
                    {
            using T = std::decay_t&amp;#x3C;decltype(x)&gt;;
            if constexpr (std::is_same_v&amp;#x3C;T, std::string&gt;) seen_upper = (x == &quot;MIXED&quot;); });
        assert(seen_upper);
    }

    // ========== 8) 异常安全（强保证）：拷贝途中抛异常，栈保持不变 ==========
    {
        using S = Stack&amp;#x3C;ThrowOnCopy, int&gt;;
        S s;
        for (int i = 0; i &amp;#x3C; 8; ++i)
        {
            if (i % 2 == 0)
                s.push(ThrowOnCopy{i});
            else
                s.push(i);
        }
        const std::vector&amp;#x3C;int&gt; snapshot = [&amp;#x26;]
        {
            std::vector&amp;#x3C;int&gt; vv;
            vv.reserve(s.size());
            for (auto const &amp;#x26;e : s)
            {
                std::visit([&amp;#x26;](auto const &amp;#x26;x)
                           {
                    using T = std::decay_t&amp;#x3C;decltype(x)&gt;;
                    if constexpr (std::is_same_v&amp;#x3C;T, int&gt;) vv.push_back(x);
                    else vv.push_back(x.v); }, e);
            }
            return vv;
        }();

        ThrowOnCopy::copy_count = 0;
        ThrowOnCopy::throw_after = 3;

        const auto old_size = s.size();
        const auto old_cap = s.capacity();
        bool threw = false;
        try
        {
            s.reserve(old_cap + 8); // 触发重分配 → 拷贝途中抛异常
        }
        catch (std::runtime_error const &amp;#x26;)
        {
            threw = true;
        }
        ThrowOnCopy::throw_after = INT_MAX;

        assert(threw);
        assert(s.size() == old_size); // 强保证：大小不变
        std::vector&amp;#x3C;int&gt; after;
        after.reserve(s.size());
        for (auto const &amp;#x26;e : s)
        {
            std::visit([&amp;#x26;](auto const &amp;#x26;x)
                       {
                using T = std::decay_t&amp;#x3C;decltype(x)&gt;;
                if constexpr (std::is_same_v&amp;#x3C;T, int&gt;) after.push_back(x);
                else after.push_back(x.v); }, e);
        }
        assert(after == snapshot);
    }

    // ========== 9) 生命周期泄漏检查 ==========
    {
        int before = Counted::live;
        {
            SmallStack&amp;#x3C;4, Counted&gt; s;
            for (int i = 0; i &amp;#x3C; 16; ++i)
                s.emplace&amp;#x3C;Counted&gt;(i);
            assert(Counted::live &gt;= before + 16);
            s.clear();
            assert(s.empty());
        }
        assert(Counted::live == before);
    }

    // ========== 10) 顶部访问与异常边界 ==========
    {
        Stack&amp;#x3C;int&gt; s;
        bool threw = false;
        try
        {
            (void)s.top();
        }
        catch (std::out_of_range const &amp;#x26;)
        {
            threw = true;
        }
        assert(threw);
        s.push(7);
        assert(std::get&amp;#x3C;int&gt;(s.top()) == 7);
        s.pop();
        assert(s.empty());
    }

    std::cout &amp;#x3C;&amp;#x3C; &quot;[OK] all saturated tests passed.\n&quot;;
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;</content:encoded><category>Vibe Coding</category><category>Data Structures</category></item><item><title>The Subtle Differences Between C and C++</title><link>https://atelier.moesegfault.dev/en/blog/2025-08-22-1-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2025-08-22-1-en/</guid><description>While C is often treated as a subset of C++, several subtle differences between the two languages remain technically consequential.</description><pubDate>Fri, 22 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Although we often treat C as a subset of C++, there remain subtle differences that cannot be safely dismissed. For the record, I did learn C before C++; that fact inevitably colors the way I read the boundary between the two languages.&lt;/p&gt;
&lt;p&gt;C++ supports function overloading, which means that function names at the assembly level can acquire a nearly anti-human form. This is also why C functions called from C++ need to be declared with &lt;code&gt;extern &quot;C&quot;&lt;/code&gt;; otherwise, the linker will not resolve them under their C symbol names. Taking GCC, the compiler I most often use, as an example, consider a function such as &lt;code&gt;int compute(int a, int b)&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;int compute(int a, int b)
{
    return a + b;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In C++, the assembly will contain:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-asm&quot;&gt;_Z7computeii:
.LFB0:
    pushq    %rbp
    .seh_pushreg    %rbp
    movq    %rsp, %rbp
    .seh_setframe    %rbp, 0
    .seh_endprologue
    movl    %ecx, 16(%rbp)
    movl    %edx, 24(%rbp)
    movl    16(%rbp), %edx
    movl    24(%rbp), %eax
    addl    %edx, %eax
    popq    %rbp
    ret
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And in C:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-asm&quot;&gt;compute:
    pushq    %rbp
    .seh_pushreg    %rbp
    movq    %rsp, %rbp
    .seh_setframe    %rbp, 0
    .seh_endprologue
    movl    %ecx, 16(%rbp)
    movl    %edx, 24(%rbp)
    movl    16(%rbp), %edx
    movl    24(%rbp), %eax
    addl    %edx, %eax
    popq    %rbp
    ret
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The same &lt;code&gt;int compute(int a, int b)&lt;/code&gt; becomes &lt;code&gt;_Z7computeii&lt;/code&gt; in C++, while in C it remains the plain &lt;code&gt;compute&lt;/code&gt;. This is not quite a matter of the language standard itself, but rather a consequence of how compilers implement namespaces and overloading through implicit renaming, a process usually called name mangling. It pushes C++ some distance away from the old fantasy of being &quot;high-level assembly,&quot; and inline &lt;code&gt;asm&lt;/code&gt; no longer feels as bare-handed as it does in C.&lt;/p&gt;
&lt;p&gt;Another problem introduced by expressive language machinery is the virtual table, or vtable.
For example, with this code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;struct test1
{
    virtual int compute(void)
    {
        return 1;
    }
};
 
struct expanded_test1 : public test1
{
    int compute(void) override
    {
        return 2;
    }
};
 
int main(void)
{
    expanded_test1 object;
    test1 &amp;#x26;reference = object;
    reference.compute();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The assembly will contain:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-asm&quot;&gt;main:
.LFB2:
    subq    $56, %rsp
    .seh_stackalloc    56
    .seh_endprologue
    call    __main
    leaq    16+_ZTV14expanded_test1(%rip), %rax
    movq    %rax, 40(%rsp)
    movl    $0, %eax
    addq    $56, %rsp
    ret
    .seh_endproc
    .globl    _ZTS5test1
    .section    .rdata$_ZTS5test1,&quot;dr&quot;
    .linkonce same_size
_ZTS5test1:
    .ascii &quot;5test1\0&quot;
    .globl    _ZTI5test1
    .section    .rdata$_ZTI5test1,&quot;dr&quot;
    .linkonce same_size
    .align 8
_ZTS14expanded_test1:
    .ascii &quot;14expanded_test1\0&quot;
    .globl    _ZTI14expanded_test1
    .section    .rdata$_ZTI14expanded_test1,&quot;dr&quot;
    .linkonce same_size
    .align 8
_ZTI14expanded_test1:
    .quad    _ZTVN10__cxxabiv120__si_class_type_infoE+16
    .quad    _ZTS14expanded_test1
    .quad    _ZTI5test1
    .globl    _ZTV14expanded_test1
    .section    .rdata$_ZTV14expanded_test1,&quot;dr&quot;
    .linkonce same_size
    .align 8
_ZTV14expanded_test1:
    .quad    0
    .quad    _ZTI14expanded_test1
    .quad    _ZN14expanded_test17computeEv
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This &lt;code&gt;_ZTV14expanded_test1&lt;/code&gt; points to the vtable. As a result, a C-style &lt;code&gt;memset(this, 0, sizeof(T))&lt;/code&gt; can destroy the object&apos;s vtable layout and produce errors that are exceptionally hard to diagnose. In C++, the safer initialization techniques are therefore initializer lists or assignments performed inside the constructor. Another curious detail is that, when RTTI (Run-Time Type Information) is enabled, the compiler also provides &lt;code&gt;_ZTVN10__cxxabiv120__si_class_type_infoE+16&lt;/code&gt; for type information.&lt;/p&gt;
&lt;p&gt;There are also smaller differences that nevertheless puncture the abstraction, such as NULL.
In &lt;code&gt;stdlib.h&lt;/code&gt; (C), we can see it&apos;s:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;#define NULL ((void *)0)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But in C++, it becomes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;#define NULL 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Therefore, if &lt;code&gt;NULL&lt;/code&gt; is used during template argument deduction, it will be deduced as an &lt;code&gt;int&lt;/code&gt;, not as a pointer. This is why C++ code should use the built-in &lt;code&gt;nullptr&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Another major topic is the difference between C and C++ memory allocation models; it cannot be reduced to a mere syntactic migration from &lt;code&gt;malloc/free&lt;/code&gt; to &lt;code&gt;new/delete&lt;/code&gt;. The central feature of C++&apos;s &lt;code&gt;new&lt;/code&gt; and &lt;code&gt;delete&lt;/code&gt; is that they automatically invoke constructors and destructors, which can introduce surprisingly well-hidden costs. Suppose there is a relatively complex type &lt;code&gt;T&lt;/code&gt;. If we write &lt;code&gt;new T[100];&lt;/code&gt;, the program calls the constructor 100 times at allocation time, rather than paying for construction only when each object is actually used. In a structure such as a hash table, where the load factor may be deliberately low and many slots may remain unused, this upfront construction becomes almost pure waste. A more modern approach is to use &lt;code&gt;std::pmr&lt;/code&gt; (Polymorphic Memory Resources) to decouple the memory allocation strategy, or to pair &lt;code&gt;std::allocator&lt;/code&gt; with &lt;code&gt;std::construct_at&lt;/code&gt;, constructing objects only when they enter use and manually destroying them when they leave it. The placement new operator can achieve a similar effect, but the former style is more idiomatic in modern C++. Since both &lt;code&gt;malloc/free&lt;/code&gt; and &lt;code&gt;new/delete&lt;/code&gt; allocate from the global heap, they typically require locking under concurrency, effectively serializing memory operations. This is why decoupled allocation strategies have long been a hard requirement in high-performance computing.&lt;/p&gt;
&lt;p&gt;In conclusion, contemporary low-level development around C often appears as a union of &quot;C and assembly.&quot; As a high-level language, C removes a great deal of mechanical labor while preserving efficiency, and its affinity with assembly makes it suitable for finely controlled domains such as the Linux kernel. By contrast, introducing C++ into a project that already contains assembly effectively creates a multi-language heterogeneous codebase; implementing a good C++ compiler is also vastly more punishing than implementing a C compiler, since the C++ template system has been Turing-complete since C++98. From this angle, C++ features such as object orientation, lambdas, and &lt;code&gt;template&lt;/code&gt; support a different route through high-performance software development: &quot;zero-cost abstraction&quot; is what remains after insisting on both low-level performance and high-level architecture. It is a compromise, and also an ambition.&lt;/p&gt;</content:encoded><category>C/C++</category><category>Assembly</category></item><item><title>The Core Qualities for Entering CS: Passion and Taste</title><link>https://atelier.moesegfault.dev/en/blog/2025-08-20-1-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2025-08-20-1-en/</guid><description>The key to entering CS is not some mystical talent, but the formation of passion and taste through methodology, metacognition, and institutional conditions.</description><pubDate>Wed, 20 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In my view, the core qualities for entering CS are only two: passion and taste. This is not a deliberate simplification performed for the sake of sounding sharp, but a conclusion distilled from a considerable body of experience.&lt;/p&gt;
&lt;p&gt;Some people may talk about whether someone is suited to computer science, or whether they possess so-called &quot;computer talent.&quot; To me, however, the attribution of &quot;talent&quot; often does little more than endow differences we cannot yet explain with an unfalsifiable sacredness, thereby purchasing a measure of psychological comfort. Even when facing a remarkably gifted young person, we can still feel the distance between that person and a mature scholar. To set talent and accumulation into a crude binary, therefore, does not truly explain the gap.&lt;/p&gt;
&lt;p&gt;We often say that someone is &quot;talented&quot; because they can infer ten things from one, or understand a point as soon as it is touched. In reality, what we are seeing is the ability to grasp the essence of things; and that ability is, to a large extent, the result of training in abstract thought. Otherwise, how could philosophy and mathematics possess such force? Some computer people believe mathematics is not essential, not because there is a complete rupture between engineering and the formal, but because they have not chosen to understand computers mathematically. They may have seen only mathematics as a tool: tools for algorithm analysis, for instance, or the graph-theoretic principles behind algorithms. They have not chosen to model types through sets, or to understand database queries through algebra. That said, I do not think this is necessarily a problem that must be corrected. Mathematics is not the only path toward taste. According to my own view:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Any formal system or architecture is a perspective-constrained reification of reality, whose utility is measured not by perfection, but by relevance.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This also explains the source of the gap and insight described above: have we, through deliberate practice, internalized a set of methodological and epistemological thinking tools as our own mode of thought? Such internalization generates tacit knowledge; what we call taste is precisely the result of examining things through that tacit knowledge. Many suggestions to &quot;find a mentor&quot; are, in essence, also a pursuit of taste: through observation and imitation, one tries to capture patterns that cannot be fully made explicit.&lt;/p&gt;
&lt;p&gt;Continuing along this analysis of &quot;taste,&quot; we arrive at a rather counterintuitive discovery: taste can also be top-down. It can begin from concise axioms, unfold along a strongly theory-driven path, and let philosophical speculation and self-reflection correct one another. Rather than relying entirely on empirical induction from behaviors and patterns, it is better to use the tools offered by analytic philosophy, allowing induction from experience and deductive reasoning to work together. Moreover, reading itself allows us to grasp the experience of others. Otherwise, what would be the point of reading literature? This is the core significance of metacognition.&lt;/p&gt;
&lt;p&gt;Yet although the model that &quot;genius comes from deliberate practice&quot; has considerable explanatory power, it remains unsatisfying when used to examine reality. If all differences can be dissolved through deliberate practice, must the unevenness of reality be reduced entirely to differences in individual agency? Here, naturally, a negation of the negation is required: this model of reality does explain how cognition can arise from deliberate practice in methodology and epistemology, but it does not explain where metacognition comes from. It remains silent on how a person first comes to recognize a certain pattern.&lt;/p&gt;
&lt;p&gt;From a broader perspective, this initial metacognition is almost radically contingent: whether one encounters a good family, whether one meets a good mentor, whether one has distinctive formative experiences and life circumstances. What many people call being &quot;taught by events&quot; can also be unified under this account, while the preceding discussion has already indicated the inefficiency of that mode of growth. Still, the variables of environment and institution are thereby better explained. We may not be able to presuppose sufficient agency in any given individual, but society can provide more opportunities for trial and error to those who hold longing and enthusiasm for knowledge, dissolve more thresholds of tacit knowledge, and at least increase the probability that they receive illumination, that first push. This is why innovation, especially creative destruction, cannot be planned into existence. It can only occur naturally within an environment whose conditions are sufficiently adequate.&lt;/p&gt;
&lt;p&gt;At this point, we can reach a higher-order understanding: genius is a product of training, but the path through which one is trained often depends on the push exerted by environment and institution; and metacognitive capacity, in turn, can greatly help a person exceed that push. This is why I maintain that, for the introductory or early stage of CS, there is no single necessary path, but there are two unavoidable elements: passion and taste. Some standardized path may at least allow a person to participate in the social division of labor. Yet a manufactured product concerned only with how many points were scored, and devoted only to the methodology of obtaining those points, obviously cannot produce genuine talent. In the end, its taste is simply too poor.&lt;/p&gt;</content:encoded><category>CS</category><category>Learning Methods</category><category>Metacognition</category></item><item><title>Halfway Up the CS Mountain: A Defense Against Average-Making</title><link>https://atelier.moesegfault.dev/en/blog/2025-08-08-1-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2025-08-08-1-en/</guid><description>Between abstraction, derivation, and the cold bench, a return to the halfway point of computer science.</description><pubDate>Fri, 08 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I recently read a passage in a friend&apos;s essay that struck me rather hard. To paraphrase:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Database System Concepts&lt;/em&gt; contains a great deal of mathematical derivation in the style of relational algebra, and &lt;em&gt;Introduction to Algorithms&lt;/em&gt; is nearly the same damned thing; there is simply too much to finish, the exam is already closing in while one is still chewing through the material, and none of it seems especially useful in more entry-level development work.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I resonate with this almost too much. When I first encountered probability and mathematical statistics, I also began from the axioms of probability and worked my way through the derivation and construction of the entire system. Knowledge, to me, has always been naturally reticular; but the price of that sense of structure is that there is always too much to learn.&lt;/p&gt;
&lt;p&gt;Was it worth it, looking back today?&lt;/p&gt;
&lt;p&gt;My answer is: it feels absurdly good, and not in a cheap way. The habit of pursuing first-principles explanations of things began with my experience of learning mathematics; at the intersection of deduction and induction, I encountered the dialectic of thesis, antithesis, and synthesis; and the habit of reading classics extensively through a critical lens pushed me toward a pursuit of reflexivity. As for that reticular structure of knowledge, it gradually rooted me in systems thinking rather than leaving me dragged around by scattered techniques.&lt;/p&gt;
&lt;p&gt;Most of the time, this path is not short on feedback. Whether it is the achievement that arises endogenously from the act of creating a complex system, or the recognition supplied by others after accomplishing uncommon things through uncommon means, both have been indispensable parts of my growth. Of course, climbing upward along a winding minor path inevitably carries the chill of sitting on the cold bench; all the more so because one often meets true masters on the same road, figures who make the mountain itself seem worthy of reverence. The halfway point may be much more sparsely populated, but the view it offers is also far broader than anything available at the foot of the mountain.&lt;/p&gt;
&lt;p&gt;So this is neither perfectionism, nor greed, nor compulsion. It is simply the pursuit of computer science at its extreme, and a nearly obstinate form of pure love. The educational imagination inherited from the industrial age, with its assembly-line pursuit of the average, was never well-equipped to understand our aspirations. If exceeding some predetermined boundary and pressing toward the edge of knowledge itself must be called greed, then the word has become an insult to the sages of old.&lt;/p&gt;</content:encoded><category>CS</category><category>Learning Methods</category><category>Epistemology</category></item><item><title>Contest-Oriented Computer Education Is Not Real CS</title><link>https://atelier.moesegfault.dev/en/blog/2025-06-07-1-en/</link><guid isPermaLink="true">https://atelier.moesegfault.dev/en/blog/2025-06-07-1-en/</guid><description>Would it not also be good to become a small bird flying freely through computer science?</description><pubDate>Sat, 07 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In my view, there is no inherently wrong time to begin studying computer science. It depends far more on the propulsion of personal interest, and on a grounded, patient act of inquiry. Why, then, does learning computing at a supposedly &quot;inappropriate time&quot; so often leave the impression that one can &quot;only solve problems&quot; and has &quot;no imagination&quot;? I would argue that this is, first of all, the responsibility of the educational and evaluative system.&lt;/p&gt;
&lt;p&gt;Computer education in China, especially before university, is highly contest-oriented in the general sense; one might even say that before university, the only people genuinely recognized as &quot;studying computing&quot; are participants in informatics competitions. The labeling of &quot;algorithms&quot; produced by this contest orientation continues to spread everywhere afterward. If the economic logic behind the envied status of algorithm positions lies in the high salaries generated by scarcity, then from another angle, there is also an elitist tendency sedimented by algorithm competitions. The shadow of the &quot;contempt chain&quot; is mottled and uneven, yet tacitly understood, sharply visible.&lt;/p&gt;
&lt;p&gt;In such an environment, contests become almost the only target into which educational energy can be poured, and algorithm problems together with fierce competition become difficult to avoid. Yet the abilities trained by algorithm competitions do not necessarily migrate into engineering ability: algorithm contests pursue proximity to theoretical limits, while engineering places greater value on stability, extensibility, reusability, and similar measures. As I once joked:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;Code with ultimate performance is only a legend from the mythic age; a large body of usable code is the true path to victory!&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I will not attempt a full proof here, given the limits of space, and will only use a simple example: the segment tree is a basic structure in algorithm competitions, yet it is hard to find in the main text of &lt;em&gt;Introduction to Algorithms&lt;/em&gt;; the red-black tree, by contrast, is so common that the C++ standard library directly provides support for it, and yet the students around me in the past were not necessarily more familiar with it than with segment trees. I have no intention of judging the culture of the competition circle, because I am not especially familiar with it. Still, much as in our analyses of the gaokao and graduate entrance examinations, once there exists some evaluative criterion, some fixed track, it is almost inevitable that an entire knowledge system will be invented around it. Starting from there, one&apos;s metacognition of computer science naturally diverges by a great distance.&lt;/p&gt;
&lt;p&gt;Seen this way, the claim that one is &quot;not suited to learn computing&quot; in childhood is not caused by the nature of computer science itself. Rather, China has not provided a sufficiently universal scheme for computer education. This backwardness is visible everywhere: in mathematics education&apos;s rejection of advanced computational tools, for instance, and in the prejudice against the internet that remained clamorous until before the pandemic. For the individual, the solution is also exceedingly simple, yet difficult to carry out: as long as one does not think within this framework, one will naturally avoid the problems manufactured by this framework.&lt;/p&gt;
&lt;p&gt;The autodidactic tradition in computer science has always been prominent; there was never any rule that knowledge must be obtained from a particular place. As &lt;em&gt;The Scholars&lt;/em&gt; puts it, &quot;credentials trap people, and the worthy and heroic sigh alike&quot;: all kinds of &quot;credentials&quot; are the treasure in the problem-solver&apos;s palm, but they are also stumbling blocks for those with larger ambitions. Once one bids farewell to these strange artificial limits, a wider sky and sea are not an extravagance.&lt;/p&gt;
&lt;p&gt;Would it not also be good to become a small bird flying freely through computer science?&lt;/p&gt;</content:encoded><category>CS</category><category>Computer Education</category><category>Learning Notes</category></item></channel></rss>