Code Review: CPP

Ғылым және технология

LIVE ON TWITCH: / theprimeagen
Check out TEEJ!
/ @teej_dv
/ teej_dv
Get in on Discord: / discord
Get in on Twitter: / theprimeagen
Got Something For Me to Read or Watch??:
/ theprimeagenreact

Пікірлер: 137

  • @rodrigolj
    @rodrigolj Жыл бұрын

    I don't feel that a cpp project is ready when there are no memory leaks to be found. I hope they fix it on v1.1

  • @user-ni2we7kl1j
    @user-ni2we7kl1j Жыл бұрын

    Lmao, this [[likely]] reminded me of this: "INTERCAL has many other features designed to make it even more aesthetically unpleasing to the programmer: it uses statements such as "READ OUT", "IGNORE", "FORGET", and modifiers such as "PLEASE". This last keyword provides two reasons for the program's rejection by the compiler: if "PLEASE" does not appear often enough, the program is considered insufficiently polite, and the error message says this; if it appears too often, the program could be rejected as excessively polite. Although this feature existed in the original INTERCAL compiler, it was undocumented"

  • @theinsane102
    @theinsane102 Жыл бұрын

    imo cpp code is more readable than rust

  • @jgndev

    @jgndev

    Жыл бұрын

    it’s true

  • @TheVimeagen

    @TheVimeagen

    Жыл бұрын

    fully agree

  • @ac130kz

    @ac130kz

    Жыл бұрын

    c++98 maybe, not the latest c++20/23 stuff

  • @froloket

    @froloket

    Жыл бұрын

    3:28 is that readable?!

  • @Artentus

    @Artentus

    Жыл бұрын

    Depends. If you write C++ like it was C then yes, it's more readable. But if you use all the modern stuff to make it behave closer to Rust it becomes much uglier.

  • @CheaterCodes
    @CheaterCodes Жыл бұрын

    The [[likely]] is a hint to the compiler to let it make assumptions it usually can't. It can then make the likely path branch-free, or emit hint instructions for the cpu (or similar). This can be useful in certain scenarios if the cpu branch prediction fails systematically (probably not here). Note that rust has something similar with the #[cold] attribute

  • @JackTheDev

    @JackTheDev

    11 ай бұрын

    oh, CheaterCodes. When you say "similar" does that include having different speeds? when it gets to the instructions, do they differ in any meaningful way? Does LLVM vs GCC have an effect on this (for C++ as Rust is only LLVM AFAIK)?

  • @vaisakhkm783
    @vaisakhkm783 Жыл бұрын

    Tom might [[likely]] be the editor for CppCoreGuidelines 😆

  • @whoopsimsorry2546
    @whoopsimsorry2546 Жыл бұрын

    [[likely]] does not help branch prediction, in fact there's nothing you can do to force branch prediction. [[likely]] optimizes branches, inlines where possible to make code run faster. Most of the compilers have an internal % system which tries to predict which branch is more likely your code to take, and based on that % it optimizes it by inlining, [[likely]] is a way for the programmer to raise that % for a certain branch. Nothing to do with branch prediction - common misconception. To be able to use [[likely]] without pessimizing instead of optimizing you need deep understanding of how your complier optimizes the code in the first place, to know where it uses lookup tables. Usually you shouldn't use that C++ feature unless you've studied the assembly your compiler generates and the performance you're getting out of it and are willing to spend the time on even the last nanosecond.

  • @horriblyterrible1121

    @horriblyterrible1121

    Жыл бұрын

    +1 This is to be used only when there is heavy operation on one branch, but is not really likely to happen. Like, say, you want to push some big strings into a set, otherwise return, and you know that the existence of a string in the set is more likely. This is where this attribute might help, and lead to lesser code generation. This will not, as correctly mentioned, predict branches. The compiler might still fully ignore it. To include this attribute in such "lightweight" branches is really unnecessary.

  • @TheVimeagen

    @TheVimeagen

    Жыл бұрын

    weird.... yeah, i have not much idea about some of c++'s things

  • @SimonBuchanNz

    @SimonBuchanNz

    Жыл бұрын

    ​@@TheVimeagen it's really just standardizing a long long history of implementation defined attributes. You don't need to care about it pretty much ever, it's a bit extra here.

  • @TsvetanDimitrov1976

    @TsvetanDimitrov1976

    Жыл бұрын

    That's not entirely true in the general case. There are architectures where a hint can be generated for the processor(for example the spus on PS3)

  • @whoopsimsorry2546

    @whoopsimsorry2546

    Жыл бұрын

    @@TsvetanDimitrov1976 Благодаря за уточнението! :)

  • @StuartLoria
    @StuartLoria10 ай бұрын

    I captured an image from the code here to create the dirty code poster, unreadable, hard to maintain, a nightmare to inherit. The ego of expressing your logic in terms of your implementation details rather than using the requirements language, robing the program of the opportunity to document the intension of the product in the code itself (while it was clear and fresh in the author's mind), assuming there will be no bugs, no changes in the requirements hence no need to open the blackbox and no changes in team roster, I love it.

  • @manwithmannynames
    @manwithmannynames Жыл бұрын

    7:20 AFAIK the way the compiler usually uses the "likely" and "unlikely" builtins is that they will place the "unlikely" branch code away from the main program flow, so the main execution path fits in less cache lines.

  • @CallousCoder
    @CallousCoder Жыл бұрын

    Ive never moved passed C++17 and I saw some very new things. I liked the likely though. But let’s be honest, it doesn’t make the code more readable. But it does optimize away a likely branch something we did in demo coding in assembly on the C64 all the time.

  • @andylyounger74
    @andylyounger74 Жыл бұрын

    [[likely]] So its maybe easier to understand if you flip it on its head and look at [[unlikely]] instead. In that case you are telling the compiler that this code path is super unusual and will let it make better inlining / conditional choices. For example an assert() implementation by definition is unlikely to fire and the assert handling code (for when it fires) could benefit from being moved out of line thus improving the general performance as less instructions and branching can be run in the non-asserting case.

  • @andylyounger74

    @andylyounger74

    Жыл бұрын

    for a [[likely]] example, think of std::vector push_back. In most cases it won't need to reallocate memory (especially if you are a good citizen and remember to reserve up-front), so could potentially benefit from the hint when it checks if it has enough capacity before the physical object copy. In this case it could potentially move the else and resize for when that fails out of line (by definition they would now be 'unlikely'), and thus get better performance (less instructions run in the common case) and benefit from better comdat folding (smaller code due to de-duplication - a common linker trick where it removes duplicated code which can also helps icache (instruction cache) efficiency --- less code == generally more potential cache hits). Think how big code could get if every 'push_back' has the explicit resize code duplicated in it,

  • @MrAbrazildo
    @MrAbrazildo11 ай бұрын

    0:30, that's because it's indeed the best so far. aka Rust+. 2:00, private is default for class, as public for struct. This private line was optional. 2:10, it's a convention, for when you want to write getter/setter with the same name. Since those f() calls will be much more often seen than the class inner data, these ones are those who change their names, by adding '_'. Not before, due to macro convention. 2:20, this convention was created by a hungarian programmer, who used to add a letter for the type of the variable. 2:47, it's entirely optional. I use to write struct, to get public as default (1st, as you say). Because if I want to use a typedef along the class definition, I need to declare it before. And since I want it to be used outside the class too, it needs to be public, to not has to break encapsulation - btw, C++ has the best from any language. 3:08, an union with tags. It's meant for when you want more than 1 variable beginning at the same address in memory. This saves memory, at the cost of only 1 may be used at a time. 3:29, it has all those scopes (::) because C++ has a philosophy of "only pay for what you use". It makes easier to write more light weight apps. So everything is subdivided into optional "sections". static_assert is for defensive code proposes, to raise compile errors if the user does something wrong.

  • @__kvik
    @__kvik6 ай бұрын

    5:27 Yes, function return type on its own line is useful for grepping function names without clever tooling; but also this is C++, where you often have like a function template returning a templated type so splitting all that to even more lines is just a reasonable thing you do and doing it for simple types as well is then just for consistency.

  • @00wheelie00

    @00wheelie00

    2 ай бұрын

    But he's using c++ 23, he can use trailing return types. It makes no sense to do that anymore.

  • @charactername263
    @charactername263 Жыл бұрын

    [[likely]] has nothing to do with the brand prediction. It's a locality optimization that means the [[likely]] branch will be close to the code preceding and succeeding the branch, with the [[unlikely]] branch further away. The only time there needs to be a potentially far jump that might cause cache misses would then only be in the [[unlikely]] path. It's for e.g critical path optimization where you might want a path that is not necessarily "hot" in that it might not run frequently, but it should run *as fast as possible* regardless. An example might be a trading system where most of the time the potential trades are rejected by a branch, but if in the minority of trades the trade is not automatically rejected you want the execution to be the fast branch. You can manipulate the branch predictor by spoofing/warming the branch but you can't cache optimize branches without the [[likely]]/[[unlikely]] language feature. It's very cool 😎

  • @ernesto906
    @ernesto906 Жыл бұрын

    so this is sort of non standard formatting for C++

  • @SimonBuchanNz
    @SimonBuchanNz Жыл бұрын

    A few things to note here, as a recovering C++ user: * For some reason, compilers start implementing standards way ahead of the year. They're adding C++27 features right now 😮 * I think private first, trailing _ for members is Google's house style? It's overall pretty nice, but the point of the underscore is so you can directly reference them without the "this->" unambiguously, so it's lame those are still there... * Standard library source is run through uglifiers so every identifier uses the reserved "_Uppercase", and every reference is fully qualified, to defend against macros breaking things. I don't think they actually edit the source like that! * noexcept is a replacement for except(), which is now completely deprecated. The difference, IIRC is that it's part of the signature so you can specialize a template if you know the generic function definitely won't throw, eg avoid putting expensive rollback handling. If/when Rust gets specialization this would be like specializing on error type !. Here it's not doing much other than checking the body can't throw, eg that every method it calls is also noexcept.

  • @widnyj5561

    @widnyj5561

    Жыл бұрын

    additional fun fact - move operators have to be noexcept, too (but I guess it depends on compiler flags, as exception during move can brake source object without, effectively losing data) - which, knowing cpp, can be just "we don't give a fuck; UB, but gib sped"

  • @simonfarre4907

    @simonfarre4907

    Жыл бұрын

    @@widnyj5561 as far as I am aware move operators definitely don't have to be noexcept. However move operations for obvious reasons, like the one you stated, should be implemented in ways that it doesn't throw. And seeing as how move operations technically don't do allocations (necessarily, they can, but for brevity's sake, lets say they don't) one can be pretty certain it's a non throwing operation. What I find unfortunate is that all my private code for hobby projects gets absolutely littered with noexcept everywhere. It should be the default.

  • @SimonBuchanNz

    @SimonBuchanNz

    Жыл бұрын

    @@simonfarre4907 you actually don't want it as a default in general, for the same reason you don't want Copy by default in Rust: it's a breaking change to remove it, while it's fine to add. If you later find out that you do want to throw (or rather, use other APIs that can throw) then you're stuffed.

  • @simonfarre4907

    @simonfarre4907

    Жыл бұрын

    @@SimonBuchanNz yeah I totally get why it's not default now, obviously. But with the privilege of hindsight, it should have been.

  • @SimonBuchanNz

    @SimonBuchanNz

    Жыл бұрын

    @@simonfarre4907 no, I mean backwards compatibility problems for your changes, not if they added it now. Imagine your public function happens to not throw exceptions, you left it at the default, then you change it to throw later. Obviously just throwing when you didn't throw before is a compat hazard, but in C++ the default assumption is anything can throw, so currently this is ok. But with nothrow, you can actually explicitly depend on the function being nothrow, most obviously by calling it from another nothrow function. Just removing the nothrow qualifier is a hard breaking change! For this reason, you should only add the qualifier when you're making it part of the API guarantee, not just because you happen to but currently throw anything. Making it the default is then a problem for two reasons: you're much more likely to accidentally expose a public API as being nothrow, and you're much more likely to accidentally depend on it being nothrow by calling from a nothrow function.

  • @topticktom
    @topticktom Жыл бұрын

    I really tried to make sense out of those Template and Type creations, but even with all the JDSL jeniusness I could come up with a simple explanation of the code.

  • @mark_fi
    @mark_fi Жыл бұрын

    [[likely]] is just a weaker and standardized version of what has existed for a long time in C/C++ e.g. in the form of __builtin_expect(). This is IIRC what also Linux kernel also uses (the likely/unlikely macros typically expand to __builtin_expect() if supported by the compiler).

  • @themohmand
    @themohmand4 ай бұрын

    I was taught the "private first, public afterwards" approach, so that part of the code seemed normal to me

  • @chikinrasshu
    @chikinrasshu11 ай бұрын

    because c++ types get stupidly long, you end up doing type function_name because std::map covers the whole line. (or auto)

  • @chikinrasshu

    @chikinrasshu

    11 ай бұрын

    and [[likely]] is a compiler intrinsic that allows it to optimize assuming the branch is true more often than false.

  • @mattmurphy7030
    @mattmurphy7030 Жыл бұрын

    Who wrote this? Returning from void at the end of a function? Do they know C++?

  • @daniels3617

    @daniels3617

    11 ай бұрын

    There is a reason for that. If you eventually add a return type to the function, you'll get a compiler error. Without the empty return, you're only going to get a warning on default settings.

  • @Xe054
    @Xe054 Жыл бұрын

    Am I the only one who didn't understand a single thing that happened in this video?

  • @leenardlacay3422

    @leenardlacay3422

    Жыл бұрын

    They're like speaking Japanese

  • @allalphazerobeta8643
    @allalphazerobeta8643 Жыл бұрын

    I would avoid using [[likely]] unless you are very sure of your assumptions. Do profile-guided optimization (PGO) not assumption guided optimization . Either-way this could help a lot with automatic unrolling of loops properly. Of course, gathering and keeping real world data up to date is difficult as Itanium proved.

  • @TheVimeagen

    @TheVimeagen

    Жыл бұрын

    yeah, i don't like the idea that i have to know what is the best course of action, i would rather have a compiler tell me :)

  • @VivekYadav-ds8oz

    @VivekYadav-ds8oz

    Жыл бұрын

    Well sometimes you know for eg: a certain condition will only hold true for the first k items in the loop. Let's say you don't want to loop over those items in a separate for-loop. I find this could be useful in those cases.

  • @allalphazerobeta8643

    @allalphazerobeta8643

    Жыл бұрын

    I just realized people might not be familiar with PGO, or profile guided optimization. You compile a version of the program that produces profile data. On gcc you use '-fprofile-generate' then you run it with inputs or data representative of typical usage. (Or you could deploy it. ) The program will create '.gcda' files. Then you recompile it with -fprofile-use and either '-O2 ' or '-O3' and whatever else you need. The profile will help the Compiler figure out how to best do the optimization. Remember, the itanium was nearly completely reliant on profiled optimization, since it's was designed to avoid doing Branch Prediction and Speculative Execution. (Which I believe was the word Primeagen was looking for)

  • @MH_VOID
    @MH_VOID Жыл бұрын

    Rust has something similar to '[[likely]]', in core::intrinsics::{,un}likely. Way it works is it takes a bool and returns it, and adjusts the likely/unlikely path to be more/less likely to be branch predicted and CPU cached, I believe. You can use it like `use core::intrinsics::likely; for i in 0..15 { if likely(i % 5 != 5) {foo()} else {bar()} }` (obviously a super contrived example but you get the point) Where do I find the full spec for this thing? I might want to have a dab at it with Z Shell or perhaps elisp. My personal specialty is in writing long shell pipeline abominations in ZSH. If I could horrify others with it that'd be nice

  • @orychowaw
    @orychowaw11 ай бұрын

    At 6:26 why are there explicit this-> strewn all over the code? There's already the underscores appended to mark member variables. Even without that is highly irregular. Unlike the private first.

  • @user-ge2vc3rl1n

    @user-ge2vc3rl1n

    11 ай бұрын

    because the -> operator is the most hackerman operator there is

  • @isodoubIet

    @isodoubIet

    7 күн бұрын

    this-> is unnecessary here, but it does make sure the name is still accessible even if defined in a base class so maybe they were future-proofing for that? Idk I wouldn't write it that way either.

  • @TehKarmalizer

    @TehKarmalizer

    6 күн бұрын

    It is to differentiate members from non-members, not public and private. Not all members will have the private underscore suffix if there are any public. It may not strictly be necessary, but some of us prefer the explicitness.

  • @peternimmo74

    @peternimmo74

    4 күн бұрын

    I hate the use of this-> which is mostly unnecessary, as you say templates is the one place where it is sometimes needed.

  • @peternimmo74

    @peternimmo74

    4 күн бұрын

    Using this-> instead of having your parameter names different from the member names makes everything ugly. Headers are usually the only place where 'using namespace' is dreadful. Using std:: is preferred in headers, but part of the reason C++ often looks so ugly is the lack of adding 'using namespace' in .cpp files. In 28 years of programming I've never found it causing problems. You would never use the full names in C#, if you did the same as alot of C++ code does in C#, it too would look pretty ugly.

  • @pabloqp7929
    @pabloqp7929 Жыл бұрын

    most iconic SWE duo

  • @Je3f0o
    @Je3f0o Жыл бұрын

    variant is template meta programming in compile time type checking added in cpp 17.

  • @simonfarre4907
    @simonfarre4907 Жыл бұрын

    I always do the member variables that are private up top, first. Because these, _always_ turn out to be the most interesting and crucial things. Think of it as attempting to look like Rust, without actually being good, like Rust.

  • @vladimirkraus1438

    @vladimirkraus1438

    Жыл бұрын

    So you are saying that you think implementation details are more important than public API? Really?

  • @simonfarre4907

    @simonfarre4907

    Жыл бұрын

    @@vladimirkraus1438 For application development - absolutely. For library development; no.

  • @simonfarre4907

    @simonfarre4907

    Жыл бұрын

    @@vladimirkraus1438 You can think of it like this; a public API is only ever important in library development. It needs to be stable, it needs to produce the same outputs, no matter it's internal details (which can change under the end-user's feet from version to version, but still produce the same output). This is where public API is of import. For application development, like say, a debugger like GDB or RR; why would the public API be the most important? They're not libraries. What's most important is their functionality, their performance. Any change to the underlying system _will_ be changes to the implementation details. This means, what data structures are being used, what is the layout, when are they read and written, so on and so forth. These are all implementation details. Rust was *brilliant* when they realized this and separated the declaration & definition of a type and it's implementation, or behavior.

  • @vladimirkraus1438

    @vladimirkraus1438

    Жыл бұрын

    @@simonfarre4907 Why do you distinguish writing library or application? All is just a code. And if implementation details are the most important to you, then you are doing something wrong. Btw. how are you ordering the methods? Private ones first at the top too? Then protected ones and public ones at the end?

  • @simonfarre4907

    @simonfarre4907

    Жыл бұрын

    @@vladimirkraus1438 False. Application development and library development differ *massively* in what requirements and constraints are placed on both the developer and end product. The ordering of methods is irrelevant, but after the definition of the actual data type, I proceed like usual, public first. There's plenty of applications that you use *right now* that do what I've said here.

  • @Messmerd97
    @Messmerd97 Жыл бұрын

    That lexer::read_char() method is really bad: A void argument, pointless usages of this, using += 1 instead of ++, a pointless return, etc. It's really weird. EDIT: It looks like the constructor also makes an unnecessary copy of the input string.

  • @TheVimeagen

    @TheVimeagen

    Жыл бұрын

    make a pr?

  • @Spongman

    @Spongman

    Жыл бұрын

    @@TheVimeagen I made a PR.

  • @asdfasdf9477
    @asdfasdf947711 ай бұрын

    That constructor 1 introduces implicit conversion from std::string 2 copies the string twice 3 const does nothing except confusing the reader 4 throw std::exception() is punishable by death 5 return does nothing at all . Noexcept makes it call terminate if exception is thrown, no stack trace. Optimising branch prediction in the code that is 10% complete is a bad sign. Requiring cpp23 and not using generator for lexer is strange, as is using both discriminator and std::variant in token. Also, std::string for multi byte token means heap allocation, use string_view or indexes for both single- and multibyte tokens, that will allow you to report line/column in error messages.-Wall, clang-format and asan are your friends.

  • @MrAbrazildo
    @MrAbrazildo11 ай бұрын

    4:09, it's just a more protected collection of integers. Not as good as Rust enums. But I guess it's possible to emulate that with an array of variants... 4:40, you can store anything in a std::map (it's a template class afterall). However, it's infamous, because it seems that it's implemented as a linked list, which is a fairly slow data struct. So often someone is seen implementing his own version of it (which I recommend, btw). 4:51, did you just swallow a bank card? 5:18, this prevents an annoying potential error from fast C initializations. 5:24, it's really bad. I don't use, neither recommend. 5:37, they are deactivated for f()s marked as noexcept. 6:57, it's a hint for the compiler, to optimize the code: it's likely to happen this than the other alternatives. And those 'this->' are unnecessary: by default the class variables are used; there's no ambiguity. 7:40, with old style enums, I like to reduce this kind of code to 3-5 lines, by creating sorted arrays, searching the char in 1, via some algorithm, and using the resulting index on the other. It's as fast as elegant. 8:20, this is just a reference for a class object that lives on the stack memory, meaning it's not allocated by the user. This token may be string or a char at a time. std::string makes automatic allocations, so it'll free its memory for you. The reference works as the borrow from Rust, I guess. What changes from it in this f() will remain after.

  • @isodoubIet

    @isodoubIet

    7 күн бұрын

    std::maps are not implemented as a linked list, they're a red-black tree (I suppose AVL might work as well, but red-black is the most common). exceptions are fantastic and very much recommended. In some cases mandatory (such as here).

  • @cheebadigga4092
    @cheebadigga4092 Жыл бұрын

    bros, LLVM have their own APT repos

  • @user-xk8cc7xo1d
    @user-xk8cc7xo1d11 ай бұрын

    im surprised both of you haven't seen private-first declarations in cpp; i had thought it was a common practice

  • @JuusoAlasuutari

    @JuusoAlasuutari

    11 ай бұрын

    The sad thing about that snippet was that ` private` at the beginning of a ` class` is redundant. You can just slap members in there, and everything before the first ` public` is implicit ` private` .

  • @user-xk8cc7xo1d

    @user-xk8cc7xo1d

    11 ай бұрын

    @@JuusoAlasuutari sure, classes are private by default but I like to be explicit about intentions

  • @JuusoAlasuutari

    @JuusoAlasuutari

    11 ай бұрын

    @@user-xk8cc7xo1d that's reasonable, I can see the upside in that. Also it makes it possible to change between class and struct with no reordering of members. Although that sort of thing isn't very common.

  • @sournois90

    @sournois90

    Ай бұрын

    ​@@JuusoAlasuutarido you mind explaining briefly to me when to use a class and when to use a struct?

  • @isodoubIet

    @isodoubIet

    7 күн бұрын

    @@sournois90 Use a class when it has invariants to maintain. Use struct when it's a bag of members with no nontrivial behaviors.

  • @AsbestosSoup
    @AsbestosSoup Жыл бұрын

    would be cool if [[ likely ]] was used to tell the compiler which branch is "more likely" (duh), so that it performs sort of a hotspot optimization like JITs do, analyzing the runtime. Just that in this case there is no analysis of course, but it assumes the programmer's directive is reflective of runtime behavior. I am really afraid JITs will get significantly better than AOT compilers, and that I'll be forced to migrate to Java 🤮.

  • @nevil2151
    @nevil21517 ай бұрын

    Would love to know the color scheme? 😅

  • @PhatPazzo
    @PhatPazzo Жыл бұрын

    Rust also has something like [[unlikely]] with the function attribute #[cold].

  • @abrarmasumabir3809
    @abrarmasumabir380911 ай бұрын

    someone know what is the color scheme?

  • @abrarmasumabir3809

    @abrarmasumabir3809

    Ай бұрын

    Dude it is rose-pine!

  • @cristianinujazznight3044
    @cristianinujazznight3044Ай бұрын

    Wow, Is like seen two old guys just talking about C99 :D Come on!!! You streamer guys should try to make a tetris in C++23, and will see THE POWER of: Spending a week to make a Cmake, Spend another week to try to add Conan/vcpkg, try to install SDL2/raylib. Then after a month, you will get beard, so you can now, Spend another week why cmake does not recognize SDL2/Raylib. And now, after two months, you are ready to start coding C++23. Thats how to do it :D

  • @oredaze
    @oredaze11 ай бұрын

    Rust - - rofl xD

  • @airman122469
    @airman122469 Жыл бұрын

    … the c++ standard library is a pain to look at. It’s worse than the code in the Boost libraries.

  • @mattmurphy7030

    @mattmurphy7030

    Жыл бұрын

    It's not meant to be looked at, it's meant to be portable. The "pain to look at" is literally a carefully guarded feature.

  • @distant6606
    @distant6606 Жыл бұрын

    trash dev catching strays again 😂

  • @TheVimeagen

    @TheVimeagen

    Жыл бұрын

    every stream

  • @chishikiendeavourer8663
    @chishikiendeavourer86636 ай бұрын

    The only reason why most programmers choose to define private member before public is to access private member variable in public function. Otherwise cpp compiler starts to puke 🤮 right back to you. It’s like I don’t recognise it, who is he/she ahhhhhhhhhhhhhhh😂

  • @TehKarmalizer

    @TehKarmalizer

    6 күн бұрын

    I’ve seen alternating private/public/private/public with members first, and then the methods.

  • @vlgrfvlgrf4007
    @vlgrfvlgrf40077 ай бұрын

    can you guys just learn some basic coding before doing this? this is beyond ridiculous. that entire 20+ line switch statement is completely pointless, the entire thing can just be: t.type = static_cast(t), t.literal = byte_; if you just learnt what an enum is. this isn't even a c++ problem, this is just a "learn to code" moment. youtube coders...

  • @Spongman
    @Spongman Жыл бұрын

    terrible c++ code

  • @musdevfrog

    @musdevfrog

    Жыл бұрын

    like your mom wrote it.

  • @Spongman

    @Spongman

    Жыл бұрын

    @@musdevfrog no, my Mom's a significantly better c++ programmer than the monkey who wrote that, and she's never coded c++.

  • @jarvenpaajani8105

    @jarvenpaajani8105

    Жыл бұрын

    What's wrong with this? Looks quite good to me. I am no C++ programmer though

  • @mishaerementchouk

    @mishaerementchouk

    Жыл бұрын

    @@jarvenpaajani8105 I'm not a developer, but the code does look peculiar. 'return's at the end of functions returning void; underscored members with "this" everywhere, "next_token" could be much shorter, say, try {t.type = type_from_char.at(byte_); t.literal = byte_; } catch (const std::out_of_range& unknown) {.. deal with it.. } read_char(); where type_from_char is a respective map. Some stuff, such as 'final's, [[likely]], std::variant, I don't understand why it's needed, but, again, not a developer, maybe it improves performance.

  • @JuusoAlasuutari
    @JuusoAlasuutari11 ай бұрын

    The fact is that CPP is the C pre-processor, which is the true pinnacle of elegance. C++ tried to beat the pre-processor's advanced feature set, failed miserably, and stole the name out of spite.

  • @isodoubIet

    @isodoubIet

    7 күн бұрын

    cringe

  • @JuusoAlasuutari

    @JuusoAlasuutari

    6 күн бұрын

    ​@@isodoubIet sad to hear about your condition

  • @isodoubIet

    @isodoubIet

    6 күн бұрын

    @@JuusoAlasuutari Didn't realize vegetables were capable of emotion

  • @exvimmer
    @exvimmer Жыл бұрын

    You don't have to nag about something that you don't understand. Just a waste of time.

  • @blazefirer
    @blazefirer Жыл бұрын

    tom modCheck

  • @TheVimeagen

    @TheVimeagen

    Жыл бұрын

    tom tom

  • @MoolsDogTwoOfficial
    @MoolsDogTwoOfficial4 ай бұрын

    std::for_each(comment.begin(), comment.end(), [](const char c) { std::cout

Келесі