Excellent video. I liked how you walk through the evaluation process. And all with a smile.
@thisismuffinmuffin5 жыл бұрын
The Best template tutorial!! What a pity Google's algorithm can't find out! You should do more.
@mateusz-czajkowski4 жыл бұрын
agree. that's pity that he stopped recording c++ videos
@tubemelf3 жыл бұрын
Very good guidance! To expand a little more information and clarify the examples, forms 2 and 3 of SFINAE are overloads instead of template specializations. In case both full and partial specializations are needed for a function, MIXING both specializations and overloads (overloads to workaround function partial specialization not being allowed) won't work when the template function is used by means of forward declaration while all its definitions (specialized and overloaded) are in a different translation unit. (Unless all overloads are also forward declared, which defeats de purpose of having the single template function forward declared in the translation unit using it). True for any mixing of specializations and overloads including those overload forms of SFINAE. Reason being, the compiler will only try to find and match one of the specializations, oblivious to any overloads. Pre C++20 concepts, I've managed to overcome this only with tag dispatching.
@tomaspyth70176 жыл бұрын
With all this stuff still a smiling C++ Programmer!!! Respect👍👍👍
@GreatTutorialChannel Жыл бұрын
The best thing is not only to demonstrate a perfect flawless interactive presentation but make some errors, show them, solve them and explain what went wrong. When you do this the first time you get 90% errors before hitting the sweet spot that compiles.
@giladreich8106 жыл бұрын
Loved your videos about templates and how you enjoy explaining them with passion! I hope you'll make some more of these videos in the future! You're truly a great teacher. One thing I would like to suggest though, if you would make a separate channel just for programming videos, that would attract much more subscribers, as some of the viewers are not interested in other videos rather than learning about programming. You could also open Patreon account and add to your videos description for people who would like to support what you do here, as the content and the examples you provided are very valuable and helpful. Big like and thanks!
@unusualfashion6 жыл бұрын
Thanks for the kind words. I've had other people suggest making another channel as well. I guess when I started I didn't think many people would be interested in this. I did it mostly to provide extra resources for some people at work, where I do some training. I haven't made any more videos in a while, but if I start up again I'll definitely keep that in mind. As for Patreon, I'll pass. :) I'm very much of the opinion that this kind of information should be provided freely by people who are happy to give it for free. I even disabled monetization on these videos so I don't get any KZbin revenue either.
@kim157427 жыл бұрын
Very good teacher!
@MrAlbinopapa5 жыл бұрын
For function overloads, you shouldn't create specializations, but instead just create the overload as if it were like fmax: template bool Equals( T lhs, T rhs ){ return lhs == rhs; } bool Equals( float lhs, float rhs ) {return true; } template specializations aren't suppose to participate in overload resolution. Just for passers by, instead of typing std::is_floating_point::value, you can also use the shortcut std::is_floating_point_v. For types, the shortcuts or aliases or typedefs end in _t and for values, the shortcuts end in _v. std::is_integral_v std::is_floating_point_v std::conditional_t std::enable_if_t I'm so glad C++17 added constexpr-if statements, now you can avoid tag dispatch and sfinae, template bool Equals( T lhs, T rhs ) { if constexpr( std::is_floating_point_v ) { return std::abs( rhs - lhs ) < static_cast(0.00001); } else { return lhs == rhs; } }
@unusualfashion5 жыл бұрын
You're quite right about the overloading for specific types. I went into it with the template specialization approach to eventually lead towards the template for all floating point types. We're not quite using C++17 where I work just yet, but I'm looking forward to using constexpr-if when we make the switch. It certainly will be nice to remove some of the clunkier SFINAE syntax.
@MrAlbinopapa5 жыл бұрын
@@unusualfashion I appreciate the response, I understand why you used functions for the specialization, the comment wasn't so much for you, but for others. Nothing more frustrating than unexpected behavior down the road because they changed compilers or some flag where certain code no longer works. Honestly, I am surprised the specialization worked. I feel as though I have tried something similar in the past and the compiler wouldn't choose my specialization functions when I was first learning about templates. I enjoyed the explanations though, I did learn something. I had always wondered about the placement and syntax of enable_if in the standard library. I could use it in the return parameter part of a function, but I was never able to figure out the empty template parameter syntax.
@xudongsun3 жыл бұрын
May I know where and how you learned all these? amazing!
@jonathanmoore56194 жыл бұрын
Echo that below. The best c++ vids on KZbin. Great way of teaching. Effortless... Seemingly.
@us59452 жыл бұрын
27:19 I think std::enable_if_t::value>* will always be a void pointer, no matter what type of T is. Is my opinion right or wrong?
@unusualfashion2 жыл бұрын
You're correct. std::enable_if takes two template arguments, the first is the boolean condition, and the second is the type that it should return, which is unrelated to the type of T that we're checking in the condition. By default, the second is void, so because it's not specified here it will return a void pointer as type, but you could specify it to be something else if you needed.
@readingchess2 жыл бұрын
Did I see The Cherno walking around in the background?
@muckvix7 жыл бұрын
Great tutorials, thx! One comment: it seems strange that the compiler would need help confirming that `conditional::type` is indeed a type. It seems evident from the syntax: if it's not a type, the `{}` right after it would be an error wouldn't it? And so couldn't the compiler simply assume it's a type from the syntax (and complain if it later discovers that it's actually not a type)? In fact, I tried to drop `typename` from `typename conditional::type{}` and MSVC 2017 compiled it without an error. Also, is there any reason to prefer the (newer) SFINAE over the (older) tag approach?
@unusualfashion7 жыл бұрын
Good catch. You're quite right. One of the problems of doing these things without a script is that I'm more likely to make mistakes I suppose. :) That wasn't a good example of dependent types. In an argument list or return statement it's evident that it must be a value of a type. You only need to add typename when you are intending to name a type. A better minimal example might be (this pasted code is probably going to look awkward...): template struct Test { using DependentType = T; }; template struct Foo { static auto Bar() { return Test::DependentType{}; //don't need typename } using Something = typename Test::DependentType; //needs typename }; In Foo, the meaning of DependentType could depend on the value of T as there could be a template specialization of Test for T in which DependentType is something other than a type, such as a member or class variable.
@unusualfashion7 жыл бұрын
I just noticed that second part of your question regarding SFINAE vs tag dispatch. Apparently the entry about SFINAE on cppreference ( en.cppreference.com/w/cpp/language/sfinae ) says: Alternatives Where applicable, tag dispatch, static_assert, and, if available, concepts, are usually preferred over direct use of SFINAE. I really can't say I have enough in-depth experience to know why those are preferred or to argue heavily in favor of one or the other when it comes to practical concerns. Personally, I prefer SFINAE over tag dispatch as I like how the constraints are more up front and visible in the function's signature and/or template types. Tag dispatch makes you dig into the function to see the constraint and then you have multiple functions that take arbitrary types like true_type and false_type without it being immediately obvious what the true_type and false_type mean. I don't currently work with a compiler that supports concepts, but when concepts are available to me perhaps I'll follow the guidance of the SFINAE page and use them instead, as they provide the same type of up front constraint declarations that I enjoy about SFINAE.
@kaustubhbansal64004 жыл бұрын
Really great tutorial. I liked your presentation style :)
@youcefsb47083 жыл бұрын
Just like [*::type] can be simplified with [*_t], [*::value] can also be simplified with [*_v] in C++17.
@illya_ike7 жыл бұрын
Very good stuff: good examples, good explanation. Subscribed!
@antiHUMANDesigns4 жыл бұрын
"People usually don't go out of their way to make void pointers"
@linus1980624 жыл бұрын
Excellent video, thank you so much!
@ahmadalastal53033 жыл бұрын
the first example of tag dispatch doesn't compile on my machine, I have VS2017 15.9 v14.16, any help ?
@unusualfashion3 жыл бұрын
Try moving the definition of the first Equals below the definition for the other two that take true_type and false_type. They should have been first so that the generic Equals can see them properly.
@ahmadalastal53033 жыл бұрын
@@unusualfashion amazing, now it is working
@interested_in_everything3 жыл бұрын
Can anyone explain why do we create a void pointer at 26:00
@Salxixons2 жыл бұрын
The idea is to get a signature that's like this during template substitution: bool equals(T lhs, T rhs, void* = nullptr); // which may look odd but equates to bool equals(T lhs, T rhs, void* some_val = nullptr); I'd rather have the void* type in enable_if_t directly rather than relying on default void eg: bool equals(T lhs, T rhs, enable_if_t::value,void*> = nullptr )
@TarunSingh-je9my5 жыл бұрын
Nice explanation.I have doubt on iterator Why we need to provide specialization in iterator template void process(Iterator begin, Iterator end) { for (; itr != end; ++itr) { process(*itr); } } why i can't write void process(Iterator begin, Iterator end) { for (; itr != end; ++itr) { process(*itr); } } please explain
@unusualfashion5 жыл бұрын
There can be many different types of iterators, so in your first example you're saying that you accept any type, and you'll call the type Iterator (and expecting for it to actually be or behave like an iterator). In the second one, it would only work for a class specifically called Iterator.
@jakobullmann75863 жыл бұрын
Is there any reason why this is not working for me? Visual Studio 2019 says: Error C2672 'Equals': no matching overloaded function found TestCpp template bool Equals(T lhs, T rhs) { return Equals(lhs, rhs, conditional_t{}); } template bool Equals(T lhs, T rhs, true_type) { cout
@jakobullmann75863 жыл бұрын
Actually I found out that if I put the definition of the dispatcher function last, rather than first, it compiles... Any idea why? Really strange...
@unusualfashion3 жыл бұрын
Hm. When I copy your code into my editor it seems to work okay. Perhaps try moving the first equals beneath the other two. Otherwise if you have the line number the error was pointing too it could help. Mostly whether it's the call Equals(1.5f, 2.5f) or Equals(lhs, rhs, conditional_t{}) that it's referring to.
@jakobullmann75863 жыл бұрын
@@unusualfashion Hey, thanks a lot for replying! The error was shown in the Equals(T lhs, T rhs) body, where the tag dispatch happens. It does compile now, if I either move up the overloaded implementations or at least declare them prior to the Equals(T lhs, T rhs). I also tried this with G++/MinGW, the situation is the same. Just that G++ was kind enough to print a hint that the declaration should come before the call site...
@KeenlyJohnas3 жыл бұрын
Oh man, I know it is powerful - but I’ve seen the dark side of this - people starting hours and hours in spots of code to figure out what is going on - ending up making simple C decorators (tools for changing the sources) for such borderline situations - it is actually way simpler to read the code later on.
@LV-ei1ce5 жыл бұрын
Amazing video !
@imteajsaimun41342 жыл бұрын
Will c++20 concepts replace sfinae?
@unusualfashion2 жыл бұрын
"if constexpr" from C++17 already removes a lot of the need for SFINAE, so no need to wait!
@burakcopur38417 жыл бұрын
Can't we override operator== for two floats, rather than having a template specialization for this case?
@burakcopur38417 жыл бұрын
Btw, you are explaining things nicely with pedagogical examples. I think you should do more videos on C++ topics.
@unusualfashion7 жыл бұрын
You're actually not allowed to override operator== for two basic types. In Visual Studio with MSVC, if you try to write it, the red underline (of doom!) is accompanied by: nonmember operator requires a parameter with class or enum type. And if you try to compile it, the error is: error C2803: 'operator ==' must have at least one formal parameter of class type If you look at the documentation about operators at: en.cppreference.com/w/cpp/language/operators The description is: Customizes the C++ operators for operands of user-defined types. Emphasis on the user-defined. It would also be somewhat scary/confusing if you could have something like an operator+ for two integers which didn't return their sum. :)
@dnavas77196 жыл бұрын
Amazing video. Thanks.
@ВиккаДевятова2 жыл бұрын
Thank you.
@ИванБотяев-д2ы5 жыл бұрын
Thank you very match. Its difficult to find lessons about templates on russian.
@RoamingAdhocrat6 жыл бұрын
Fantastic - thanks so much!
@sebastianwilke6263 жыл бұрын
Regarding what you showed at the end: "The behavior of a program that adds specializations for is_floating_point or is_floating_point_v (since C++17) is undefined." ( en.cppreference.com/w/cpp/types/is_floating_point )
@viraatchandra84986 жыл бұрын
Thank you so much!!
@Foo-i1v5 жыл бұрын
thank you so much
@MDM6666667 жыл бұрын
Dudeeeeeee, you have a seriously long neck. These are some good tutorials, though.
@unusualfashion7 жыл бұрын
I am extremely amused that you pointed that out. I do have a seriously long neck, and it's particularly noticeable when I stand next to someone of similar height, because then you can see how low my shoulders are relative to that other person and just how much of my height comes from my neck.