C++ Weekly - Ep 259 - CRTP: What It Is, Some History and Some Uses

Поділитися
Вставка
  • Опубліковано 28 лип 2024
  • ☟☟ Awesome T-Shirts! Sponsors! Books! ☟☟
    Upcoming Workshop: C++ Best Practices, NDC TechTown, Sept 9-10, 2024
    ► ndctechtown.com/workshops/c-b...
    Upcoming Workshop: Applied constexpr: The Power of Compile-Time Resources, C++ Under The Sea, October 10, 2024
    ► cppunderthesea.nl/workshops/
    T-SHIRTS AVAILABLE!
    ► The best C++ T-Shirts anywhere! my-store-d16a2f.creator-sprin...
    WANT MORE JASON?
    ► My Training Classes: emptycrate.com/training.html
    ► Follow me on twitter: / lefticus
    SUPPORT THE CHANNEL
    ► Patreon: / lefticus
    ► Github Sponsors: github.com/sponsors/lefticus
    ► Paypal Donation: www.paypal.com/donate/?hosted...
    GET INVOLVED
    ► Video Idea List: github.com/lefticus/cpp_weekl...
    JASON'S BOOKS
    ► C++23 Best Practices
    Leanpub Ebook: leanpub.com/cpp23_best_practi...
    ► C++ Best Practices
    Amazon Paperback: amzn.to/3wpAU3Z
    Leanpub Ebook: leanpub.com/cppbestpractices
    JASON'S PUZZLE BOOKS
    ► Object Lifetime Puzzlers Book 1
    Amazon Paperback: amzn.to/3g6Ervj
    Leanpub Ebook: leanpub.com/objectlifetimepuz...
    ► Object Lifetime Puzzlers Book 2
    Amazon Paperback: amzn.to/3whdUDU
    Leanpub Ebook: leanpub.com/objectlifetimepuz...
    ► Object Lifetime Puzzlers Book 3
    Leanpub Ebook: leanpub.com/objectlifetimepuz...
    ► Copy and Reference Puzzlers Book 1
    Amazon Paperback: amzn.to/3g7ZVb9
    Leanpub Ebook: leanpub.com/copyandreferencep...
    ► Copy and Reference Puzzlers Book 2
    Amazon Paperback: amzn.to/3X1LOIx
    Leanpub Ebook: leanpub.com/copyandreferencep...
    ► Copy and Reference Puzzlers Book 3
    Leanpub Ebook: leanpub.com/copyandreferencep...
    ► OpCode Puzzlers Book 1
    Amazon Paperback: amzn.to/3KCNJg6
    Leanpub Ebook: leanpub.com/opcodepuzzlers_book1
    RECOMMENDED BOOKS
    ► Bjarne Stroustrup's A Tour of C++ (now with C++20/23!): amzn.to/3X4Wypr
    AWESOME PROJECTS
    ► The C++ Starter Project - Gets you started with Best Practices Quickly - github.com/cpp-best-practices...
    ► C++ Best Practices Forkable Coding Standards - github.com/cpp-best-practices...
    O'Reilly VIDEOS
    ► Inheritance and Polymorphism in C++ - www.oreilly.com/library/view/...
    ► Learning C++ Best Practices - www.oreilly.com/library/view/...
  • Наука та технологія

КОМЕНТАРІ • 92

  • @cppweekly
    @cppweekly  3 роки тому +9

    As others have pointed out on Twitter, this is not necessarily "Best Practices" for using CRTP. My goal was to show what the concept is and potential use cases. There are MANY possible uses.
    Check out this Twitter note from Bjorn Fahller for more info twitter.com/bjorn_fahller/status/1361362603126251525

  • @mogenshansen7210
    @mogenshansen7210 3 роки тому +9

    It was James Coplien who coined the pattern, og described it in the magazine C++Report in the mid 90's.
    His amazing book "Multi-Paradigm DESIGN for C++" provides a solid design foundation for CTRP (among other things).
    It is very similar to pure virtual functions, declared in the base class and defined in the derived classes, but bound at compile time instead of run time.

    • @jonathanoconnor5838
      @jonathanoconnor5838 3 роки тому

      I couldn't find any use of CRTP in Coplien's earlier book "Advanced C++" published in 1992. The Multi-Paradigm book dates from 1998. Even there, he doesn't name the pattern. So, I wonder who coined the term.

    • @mogenshansen7210
      @mogenshansen7210 2 місяці тому

      It was coined by Jim Coplien (who I personally know) i an article in C++ Report, februar 1995. The article was named "Curiously Recurring Template Pattern"

  • @keris3920
    @keris3920 3 роки тому +4

    Great talk. This is perhaps my favorite pattern; it's incredibly useful.

  • @davidbell304
    @davidbell304 3 роки тому +7

    CRTP is great. I started in C++ using ATL for my own things so it's kind or normal for me. These days I think it's a good fit for embedded programming, if you have multiple embedded modules in a project you use it to split common logic off from hardware interaction.
    inline Derived_T& derived_me() {return static_cast(*this);} // is a handy function

  • @Alex-fr2td
    @Alex-fr2td 3 роки тому +54

    will there be an episode on .mpp C++ modules?

  • @akj7
    @akj7 3 роки тому +5

    This was really a nice example.
    It would nice to mention that CRTP is also called static polyformismus and one reason why it is used is to avoid the cost of virtual functions.

    • @lucy-pero
      @lucy-pero 2 роки тому +1

      That makes no sense.
      static dispatch vs dynamic dispatch are different things, with different capabilities and pros and cons. You don't use static dispatch to "avoid the cost of virtual functions". you use dynamic dispatch when it's appropriate to do so, same with static dispatch. You can only use static dispatch (which would be this) if you can know the specific type of the data at compile time.

    • @akj7
      @akj7 2 роки тому

      @@lucy-pero No, they are not the same thing. Everything you have written is wrong.

    • @lucy-pero
      @lucy-pero 2 роки тому

      @@akj7 what

    • @akj7
      @akj7 2 роки тому

      @@lucy-pero I misread your first comment. Concerning "avoid the cost of virtual functions", you replied: "you use dynmaic dispatch when its appropriate". Agreed, but how can the user know what is appropriate? Someone coming from Java or C# or doesn't know what appropriate is, would implement a pure virtual class and inherit from it to ascertain consistencies. Here static polymorphismus could have work nicely as there is no need to pay the price of dynamic dispatch.

    • @lucy-pero
      @lucy-pero 2 роки тому

      @@akj7 sure, if you don't even know what you're doing then yeah it'd be nice to learn that there are 2 different ways of doing some things haha.. I'd just argue that this CRTP thing is horrible and i'd do it in some other way or just switch to Rust but I believe this about most C++ things....

  • @Arwahanoth
    @Arwahanoth Рік тому

    I used CRTP a while ago to implement a "mixin" providing a stack allocated object pool of "typename CRTP" (and size).

  • @sephirostoy
    @sephirostoy 3 роки тому +4

    Have used it recently to know whether some virtual functions were defined in inherited classes in a non-intrusive way:
    struct IBase
    {
    virtual bool HasFunc() const = 0;
    virtual void Func() {}
    };
    template
    struct BaseT : public IBase
    {
    virtual bool HasFunc() const override
    {
    return !std::is_same_v;
    }
    }
    This allows me to detect if Func() has been overloaded and do things accordingly at call site.

  • @URTonemanclan
    @URTonemanclan 3 роки тому +1

    llvm/clang appears to use this quite a bit within the AST code

  • @DrUlrih
    @DrUlrih 3 роки тому +1

    what about a deletion of specific constructor or function with base crtp template class?..

  • @yan-amar
    @yan-amar 3 роки тому +6

    It should be renamed "curiously *recursive* template pattern" since it not so much recurring nowadays.

    • @cppweekly
      @cppweekly  3 роки тому

      But it's also not recursive

    • @yan-amar
      @yan-amar 3 роки тому +1

      @@cppweekly Well, it's a class inheriting another that is defined in terms of the first, isn't it ?

    • @yan-amar
      @yan-amar 3 роки тому +1

      But yeah i'm stretching the definition. It may be thought as recursive on a conceptual level, as a type referring to itself in its definition. In practice, it's no more recursive than a class holding a pointer to itself. So not recursive, really.

  • @nvmcomrade
    @nvmcomrade 3 роки тому +5

    When would you correctly use that? When I learn about some new and cool for me thing I immediately try to put it in use into my code base and I ruin everything. So, this time before I destroy my sanity I want to check for a proper use case. I know it could be used for static polymorphism, but when is that a good idea?

    • @cppweekly
      @cppweekly  3 роки тому +5

      I think the correct answer in C++, 95% of the time, is when a given technique (CRTP, whatever) results in the most simple, most maintainable code, then it's the right time to use that technique.
      The trick is knowing all the possibilities and be willing to find the best one when working on new code.

  • @user-zw3im6si4x
    @user-zw3im6si4x 3 роки тому +1

    The most famous example of CRTP pattern is std::enable_shared_from_this. But occasionally nobody remember enable_shared_from_this class in CRTP context.

    • @killerbee.13
      @killerbee.13 3 роки тому

      There was some reason I was irritated about std::enable_shared_from_this because there's a line in the standard that explicitly requires std::shared_ptr to do the wrong thing in a certain case, but I have now completely forgotten what that behavior even was, because I've only used shared_ptr like twice in total and just never really needed std::enable_shared_from_this. Anyways, as far as it goes it is a good example of using CRTP for something other than just operators.

    • @user-zw3im6si4x
      @user-zw3im6si4x 3 роки тому

      @@killerbee.13 enable_shared_from_this widely and naturally used in async applications like boost::asio based servers. Common problem with this class is not freeing memory until last weakptr alive.

  • @myhardware1420
    @myhardware1420 3 роки тому

    hi, you probably have forgot to add this episode to the c++ weekly playlist

  • @raulsantandertirado4400
    @raulsantandertirado4400 Рік тому

    Wait so you can update how an operator works?! Awesome!

  • @MatthewWalker0
    @MatthewWalker0 3 роки тому

    A thing about this that I ran across once, is that there's no compile message for 'doing the wrong downcast', as long as the compiler knows how to do the Base -> Derived cast that you're telling it to do. Such as specifying an existing class derived from the Base for the CRTP parameter. This can easily happen if a copy-paste error is made from an existing derived class' definition, which is especially common when using this for 'mixins'. eg godbolt.org/z/8erWej

  • @EpicSnakes
    @EpicSnakes 3 роки тому +2

    you can code generic singleton using this pattern

  • @su1cidity
    @su1cidity 3 роки тому +7

    Not that it matters, but isn't the 2nd condition in operator== incorrect? Shouldn't it be `&& !( ...rhs < ...lhs )`?

    • @SagaxCorvinus
      @SagaxCorvinus 3 роки тому +6

      What he wrote was !(a < b || b < a), which is equivalent to what I assume you are suggesting, that is !(a < b) && !(b < a).

    • @cppweekly
      @cppweekly  3 роки тому +25

      De Morgan's laws for future readers

    • @su1cidity
      @su1cidity 3 роки тому +8

      @@SagaxCorvinus You're correct. My eyes misplaced a parenthesis. The static casts and long lines make that hard to read 😅

    • @VioletGiraffe
      @VioletGiraffe 3 роки тому +3

      @@su1cidity, and that's why prettier, better-formatted and better-structured code is always better! Aesthetics and readability matters in programming, even though the compiler doesn't care.

    • @MaceUA
      @MaceUA 3 роки тому

      At first I read it wrong as well, because I didn't notice where the first parenthesis was closed. Code like this gets confusing without proper formatting.

  • @perfectionbox
    @perfectionbox 3 роки тому +2

    Unreal Engine uses CRTP to implement TSharedFromThis, so a class can provide a shared pointer to itself

  • @267praveen
    @267praveen 2 роки тому

    So when a polymorphic type knows the type it will get , then it can use CRTP?

  • @graham12345dd
    @graham12345dd Рік тому

    Hi Jason,
    Loving your videos, thank you.
    Im not seeing the advantage hereat all (its my problem, not yours) ;)
    If we removed templates altogether from this code and MyStruct just inherited from SomeTemplate (no template parameters anywhere, this code would still work and be much easier to read and work with IMHO).
    Is CRTP adding the fact that the static_cast is definitely safe. Actually now that I'm writing this this question, I realise that without templates, "SomeTemplate" could be the base class of ANYTHING, so the static casts wouldn't work.
    I've just answered my own question. Doh!
    Anyways, great videos

  • @DBZM1k3
    @DBZM1k3 3 роки тому +1

    What is the benefit to doing this over writing the comparisons before the spaceship operator? Is it just that it saves you from bloating your source code as well as saving time because you only have to provide the less than comparison?

    • @keris3920
      @keris3920 3 роки тому +5

      It's kind of the opposite of an interface. Implementation is provided in the base class, so functionality can be injected into a class.
      For instance, I wrote a linear algebra library based on this pattern. There are base classes such as 'constructable', 'iterable', 'dimensionable', etc to provide implementation details. As a consequence, my matrix class is completely empty, and I can reuse code between "matrix", and "vector", and "tensor". And I can create all kinds of optimizations by defining "diagonal_matrix", "expression", in just a few lines.
      So if done correctly, it's efficient, saves a lot of code, and quite honestly allows you to organize member functions/constructors/etc for all your classes in one place, making the code much cleaner (in my opinion).

    • @DBZM1k3
      @DBZM1k3 3 роки тому

      @@TomasPruzina-uw9ql In my workplace we use the latest standards for our simulators. The spaceship operator has arrived with C++20 so there's no reason for my workplace not to use it.

  • @koyrehme4361
    @koyrehme4361 3 роки тому +1

    Initialisms are a subset of acronyms. Either term is acceptable here, though initialism is more precise.

    • @technologicalwaste7612
      @technologicalwaste7612 3 роки тому

      It is the other way around. Not all initialisms are read as words. The subset of initialisms that are read as words are acronyms. Made-up words like 'Nasa' for NASA are allowed as acronyms; the usage is what defines them. e.g. Nobody reads 'Yoosa' for USA, so it is an initialism. CTRP is unreadable as a word ('Seeterp'?) so it is also an initialism.

    • @koyrehme4361
      @koyrehme4361 3 роки тому

      @@technologicalwaste7612 When you pronounce it as a word it's called a "word acronym" which is another subset of acronyms. There are other ways to form acronyms than just getting the initial letters, which wouldn't include initialisms. Some people (like you) use the term "acronym" to only refer to word acronyms, and that's fine, too.

    • @technologicalwaste7612
      @technologicalwaste7612 3 роки тому

      @@koyrehme4361 Would your definition of acronym cover abbreviations such as 'NiCad' for Nickel-cadmium battery?

    • @koyrehme4361
      @koyrehme4361 3 роки тому

      @@technologicalwaste7612 Yes. Another good example is RADAR (RAdio Detection And Ranging).

  • @japedr
    @japedr 3 роки тому

    Shouldn't you also delete the base class constructor to make the static_cast safer?

    • @TheXanikseo
      @TheXanikseo 3 роки тому

      Static cast is always safe to use AFAIK

  • @AM-qx3bq
    @AM-qx3bq 3 роки тому +2

    Cool explanation, but what's the advantage? Why not just define operator== in the original class?

    • @mixmasterlandberg
      @mixmasterlandberg 3 роки тому

      Someone else much more competent than me will have to elaborate, but it's basically about decoupling logic from a data storage class. MyStruct should really only handle the int data member, so he moves the logic for equals to the mixin class.

    • @michaelwaters1358
      @michaelwaters1358 3 роки тому +5

      It allows for code reuse. If you have a bunch of classes that need comparison operators, you now only need to write == / != / > etc one time in the base, and so you only have to provide the custom logic for each class in terms of the less than operator. So you save rewriting all the comparison operators.

  • @93davve93
    @93davve93 3 роки тому +2

    This feels very hacky, but kinda interesting... Are there any other use cases than comparison operator overloading?

    • @theRECONN
      @theRECONN 3 роки тому +4

      Jason showed the "quick and hacky way". Usually with CRTP you make utility functions for the static_cast. Biggest advantage of CRTP is static polimorphism I would say. You can sort of implement concepts with it. But just "sort-of" as concepts are way more convenient.

    • @user40586
      @user40586 3 роки тому +1

      dunno if there might be a better way to do this than CRTP, but I've used this Singleton header in my own projects, originally seen here: github.com/ElDewrito/ElDorito/blob/master/ElDorito/Source/Utils/Singleton.hpp
      So your child class can implement a simple static interface with:
      static RetType DoXThing(){ return Instance().DoXThingImpl(); }
      RetType DoXThingImpl(){ /* logic */ }

    • @93davve93
      @93davve93 3 роки тому

      @@theRECONN Yeah, I thought about concepts as well, but haven't read that much about the subject.

    • @frydac
      @frydac 3 роки тому +1

      It's a way for a derived class to customize its baseclass without using virtual functions (and their runtime overhead).
      It's a bit cumbersome to use as the functions that the derived class should implement don't have a function signature listed anywhere, the baseclass just uses them. This is an issue for all kinds of templates.. concepts could help with this (but I don't have any experience with them)

    • @atimholt
      @atimholt 3 роки тому +4

      A hack inside a black box is just a nice box. 😉

  • @thfyk
    @thfyk 3 роки тому

    CRTP -- dark magic in C++

  • @therenaissance8322
    @therenaissance8322 3 роки тому

    You seemed to have forgotten to put in the notes.

  • @charlieandfedericabeattie3432
    @charlieandfedericabeattie3432 3 роки тому

    Recurring *Not* recursive. I made that mistake for many years.

  • @267praveen
    @267praveen 3 роки тому

    I want to use this and make people scratch their heads the way I did !!!

  • @maartenofbelgium
    @maartenofbelgium 3 роки тому

    Why is the operator== declared as `bool operator==(const SomeTemplate &rhs) const` and not as
    `bool operator==(const CRTP &rhs) const`?

    • @minirop
      @minirop 3 роки тому

      because it is defined inside SomeTemplate.

    • @maartenofbelgium
      @maartenofbelgium 3 роки тому

      @@minirop SomeTemplate has CTRP as a template typename, so it can be directly used as argument or return type.

    • @eLBehmo
      @eLBehmo 3 роки тому

      not sure, but maybe something for ADL?? I use your example...

    • @minirop
      @minirop 3 роки тому

      @@maartenofbelgium I thought both parameters had to be of the same type. doesn't seem to be the case. but I never saw operator whose types were not the type of their class, so.

    • @maartenofbelgium
      @maartenofbelgium 3 роки тому +1

      @@minirop std::vector operates on and returns items of type T/T&.

  • @broken_abi6973
    @broken_abi6973 3 роки тому

    I tend to find CRTP annoying for code reuse, because it requires that the derived class members are public to be accessible from the base.

    • @cppweekly
      @cppweekly  3 роки тому

      You should be able to declare the CRTP base class as a friend of the derived class that uses it, and then still use hiding in the derived class.

    • @broken_abi6973
      @broken_abi6973 3 роки тому

      @@cppweekly True. However, seeing "friend" outside of library code disturbs me for some reason, and makes me reconsider the use of other techniques to tackle the problem.

  • @trendingtopicresearch9440
    @trendingtopicresearch9440 3 роки тому

    Arent concepts replacing this?

    • @cppweekly
      @cppweekly  3 роки тому

      Historical context is always useful, even if most use cases for CRTP go away.

  • @ivanzvonimirhorvat9744
    @ivanzvonimirhorvat9744 3 роки тому +3

    Add some underscores, and make it a library

  • @danielrhouck
    @danielrhouck 3 роки тому

    I’d guess that if someone is watching this in the distant future and doesn’t know why you’d go on a tangent about whether on-site training is a thing in January 2021, it might not be for them either, because you might have retired or something

  • @benjaminshinar9509
    @benjaminshinar9509 3 роки тому +1

    if you happen to be watching this video in the distant future and you have no idea what 'on site' means...