Entries:
Comments:
Posts:

Loading User Information from Channel 9

Something went wrong getting user information from Channel 9

Latest Achievement:

Loading User Information from MSDN

Something went wrong getting user information from MSDN

Visual Studio Achievements

Latest Achievement:

Loading Visual Studio Achievements

Something went wrong getting the Visual Studio Achievements

Stephan T. Lavavej - Core C++, 5 of n

Download

Right click “Save as…”

In Part 5, Stephan teaches us about Explicit and Partial Specialization of class and function templates.

From MSDN ->

Class templates can be specialized for specific types or values of the template arguments. Specialization allows template code to be customized for a specific argument type or value. Without specialization, the same code is generated for each type used in a template instantiation. In a specialization, when the specific types are used, the definition for the specialization is used instead of the original template definition. A specialization has the same name as the template of which it is a specialization. However, a template specialization can be different in many ways from the original template. For example, it can have different data members and member functions.

Use specialization to customize a template for a specific type or value. Use partial specialization when the template has more than one template argument and you only need to specialize one of them, or when you want to specialize behavior for an entire set of types, such as all pointer types, reference types, or array types.

// explicit_specialization1.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

// Template class declaration and definition
template <class T> class Formatter
{
   T* m_t;
public:
   Formatter(T* t) : m_t(t) { }
   void print()
   {
      cout << *m_t << endl;
   }
};

// Specialization of template class for type char*
template<> class Formatter<char*>
{
   char** m_t;
public:
   Formatter(char** t) : m_t(t) { }
   void print()
   {
      cout << "Char value: " << **m_t << endl;
   }
};

int main()
{
   int i = 157;
   // Use the generic template with int as the argument.
   Formatter<int>* formatter1 = new Formatter<int>(&i);

   char str[10] = "string1";
   char* str1 = str;
   // Use the specialized template.
   Formatter<char*>* formatter2 = new Formatter<char*>(&str1);

   formatter1->print();
   formatter2->print();
}

See part 1: Name Lookup
See part 2: Template Argument Deduction
See part 3: Overload Resolution
See part 4: Virtual Functions

Tags:

Follow the Discussion

  • Excellent stuff. Part of the reason I enjoy Stephan's stuff so much is its cross platform nature. I get to play with this material in XCode 4.5.1  as well as Visual C++ 2012.

    More of Stephan please!

  • KennyKenny

    Oh, I was waiting for this new part from long time ago.
    Thank you Stephan.

  • Finally some "normal C++" video and as usual explained at the best level.

    Thanks for the series

  • Keep it coming Stephan ! Great work !

  • TommySTommyS

    "When writing a specialization,
    be careful about its location;
    or to make it compile
    will be such a trial
    as to kindle its self-immolation."
    There is a poet in the Committee :-P

    Great joy watching you STL, as always! :-)

  • Great Big Smile another C++ video from Stephen.

    Template Specialization,
    ive seen a factorial specialization like that.

     

    template <int N>
    struct Factorial {
        enum { value = N * Factorial<N - 1>::value };
    };
    
    template <>
    struct Factorial<0> {
        enum { value = 1 };
    };
    
    // Factorial<4>::value == 24
    // Factorial<0>::value == 1
    const int x = Factorial<4>::value; // == 24
    const int y = Factorial<0>::value; // == 1

    Cant wait for part 5, and a meta programming tutorial will be fantastic

  • C64C64

    Thanks STL and Charles for this.

     

  • Thanks for another great episode STL. The gap between this and the previous video was so long I had forgotten about this series. Was delighted to see it on up on C9 yesterday.

  • RicodeRicode

    Thank you for the video!

    I run lately into problem where I have to check inside class template if it was instantiatied with specific specialization (forgive me if I messed up explaining this), if it's a pointer to be more precisely.

    template <typename T> struct MyClass {
    MyClass() {
    //checking if T is a pointer, if so do some extra stuff
    //do other stuff
    } };

    My first thought was to use is_pointer<T> from type_traits which worked just fine, then I got asked to do this w/o type_traits so I ended up making help structs

    template <typename T> struct Help{ bool IsPointer(){return false;}};
    template <typename T> struct Help<T*>{bool IsPointer(){return true;}};

    or with static functions like you suggested in the video.

    My question is, whats acctually the best way to do this. I got into type_traits is_pointer guts and I noticed that it removes cv_qualifiers before comparasion if I remember correctly. Does it make it any better?

    Thanks in advance.

  • STLSTL

    Ricode> template <typename T> struct Help{ bool IsPointer(){return false;}};

    Help<T>::IsPointer() is an ordinary member function. It can be tested at runtime, but not compiletime. (A static member function would behave identically.) When inspecting types in order to do things differently depending on the properties you find, you often need compiletime tests. For example, you might want to write *t + *u for pointers to integers, but t + u for integers themselves. Note that you cannot do this with a simple "if" test at runtime, because *t + *u is not valid for integers, and t + u is not valid for two pointers.

    <type_traits> provides compile-time answers with static const bool data members. (Other people use enums here.) This can be used, with mechanisms like tag dispatch (the preferred technique in VC's STL) or helper struct specializations, to perform compiletime tests.

    (C++11 constexpr changes things here.)

    > I got into type_traits is_pointer guts and I noticed that it removes cv_qualifiers before comparasion if I remember correctly.

    That's required by N3376 20.9.4.1 [meta.unary.cat]/2: "For any given type T, the result of applying one of these templates to T and to cv-qualified T shall yield the same result." In English, is_pointer considers both "X *" and "X * const" to be pointers. The top-level cv-qualifier doesn't radically change the nature of the type. (If you care about top-level cv-qualification, you can always ask is_const.)

    However, the important thing here is that is_pointer<T> derives from either true_type or false_type. Therefore you can overload a helper function on true_type and on false_type, and pass it an is_pointer<T>() argument, and the desired overload will be selected. That will avoid calling the undesired overload, whose guts may not compile for the given type.

  • RicodeRicode

    Thanks for explanation, haven't thought of that, was only testing is for simple "couts" to recive information, problem came when I tried to do some computations with types.

  • CharlesCharles Welcome Change

    @geeyef: Sorry about that. I could have posted sooner, but alas I've been underwater on a large software project.

    C

  • HumanBladeHumanBlade

    How can the posted example possibly be STL code without a Meow class? And where are my vectors of widgets?

    Great stuff as always from Stephan. :)

    Thanks for this, the past ones and all those in the past. If only we could clone you to do Channel9 monthly...

    Oh and a std::future<thank_you> for all those std::async(possible_videos).

  • STLSTL

    HumanBlade> How can the posted example possibly be STL code without a Meow class?

    It isn't mine.  :->  Looks like it's from MSDN (the top comment is in their style).  Additionally, I wouldn't write code that leaked formatter1 and formatter2, even in a toy example.

    I filmed Part 6 yesterday!

  • Thank you.

  • Alex KrycekAlex Krycek

    Thanks a lot.

  • DEAR STL , thanks for another GREAT GREAT GREAT video Smiley

  • STLSTL

    I am so lucky to have such dedicated viewers. And to be able to make cat noises on camera.

  • IonelIonel

    Thanks for your great videos.
    I have a question about your presentation. When you talk about function specialization and overloading, you give the example:
    template <typename T> void meow(T);
    template <typename X> void meow(X*);
    If I understand your presentation correctly, these are two overloads, not template specialization. In this case, why the call to meow(double*) compiles? In my opinion, both functions are a perfect match (with T=double* and X=double), so the overload resolution should complain about that.

  • STLSTL

    Correct, they're overloads, and after template argument deduction they're both exact matches. Ordinarily that would be ambiguous, but a tiebreaker steps in - "partial ordering of function templates" (N3376 14.5.6.2 [temp.func.order]). This process figures out whether one function template is "more specialized" than another. It closely imitates the effects of partial specialization for class templates.

    Partial ordering is easier for humans to do than compilers. Given two function templates f() and g(), f() is more specialized than g() if f() matches a strictly smaller infinite universe of stuff than g() does.  For example, meow(X *) is more specialized than meow(T).

    As a tiebreaker for equally good matches, overload resolution (13.3.3 [over.match.best]) prefers more specialized function templates.  (This is right next to the other tiebreaker rule, that non-templates are preferred to templates when they're equally good matches.)

    The way that a compiler performs partial ordering is really clever (but potentially confusing). Given f()'s function parameters, it generates imaginary function arguments and sees (via template argument deduction) whether it could call g() with them.  Then it reverses things, taking g()'s function parameters, generating imaginary function arguments, and seeing whether it could call f() with them.  (Partial ordering is a competition between function templates, without regard to the actual arguments you're passing.)

    Given meow(T), the compiler generates an imaginary argument of type TT and sees if it can call meow(X *) with it.  It can't.  Then given meow(X *), the compiler generates an imaginary argument of type XX *, and sees if it can call meow(T) with it.  It can.  This allows the compiler to determine, in just two steps, which function template (if any) matches a strictly smaller infinite universe of stuff, without actually generating an infinite number of possible arguments. Clever!

    For another example, if all capital letters are template parameters, and you have:

    kitty(A, B) // #1

    kitty(C *, D) // #2

    kitty(E, F *) // #3

    Then:

    (int, int) selects #1.  (#2 and #3 fail template argument deduction.)

    (pointer, int) selects #2.  (#1 is also an exact match, but #2 is more specialized than #1.  #3 simply fails template argument deduction.)

    (int, pointer) selects #3.  (#1 is also an exact match, but #3 is more specialized than #1.  #2 simply fails template argument deduction.)

    However, (pointer, pointer) is ambiguous.  All three are exact matches, so partial ordering has to tiebreak.  #1 loses to both #2 and #3 so it's out of the picture.  However, #2 is not more specialized than #3 and vice versa, for the reasons explained above (both humans and compilers can see this).  This fact is a property of the function templates, it just wasn't relevant for the (int, int), (pointer, int), and (int, pointer) arguments.  Only the (pointer, pointer) arguments put #2 and #3 into competition with each other, at which point overload resolution tries to figure out which one is better.

    Adding a kitty(G *, H *) overload (#4) fixes things.  It doesn't change the fact that #2 isn't more specialized than #3 and vice versa, it just makes it irrelevant.  Given (pointer, pointer) arguments, #4 is more specialized than *all* of #1/#2/#3, so #4 wins.

    Hopefully that clarifies things.

  • IonelIonel

    Thank you, everything is clear now.

    In the video, your exemple with
    kitty(A, B) // #1
    kitty(C *, D) // #2
    kitty(E, F *) // #3
    was given using a class template specialization. I didn't know that the same rules applies to the function templates, even in the case of overloading.

    Clever compiler.

  • STLSTL

    Part 6: http://channel9.msdn.com/Series/C9-Lectures-Stephan-T-Lavavej-Core-C-/STLCCSeries6

  • Uri LondonUri London

    Stephan, your talk basically discussed one kind of template specialization ... basically when T (the template argument) is a pointer.
    In addition to: template<typename T> struct S<T*> ..., I'm familiar with T[] and T&. What would be helpful if you have a talk discussing other specialization options, such as T is derived from something, or T has a certain trait (using <type_traits> header file).

    Also, I don't think the following was discussed enough. If X is a templates, and A and B are two classes, with B derived from A, it is not true that X<A> is derived from X<B>. Same is going with template specialization - which has nothing to do with inheritance. However, my question is what can we do to workaround this. For example, I've X<typename T> a class template, and I've X<int> a specialization template. Is there any way I can have some of the methods of the general template X<T> in X<int> without retyping it?

  • You skimmed over extern templates and you told that you really didn't use such thing. Please imagine this, I really want to make some dynamic library for other people to use, but almost all of the C++ standard library is template classes and I am not able to safely export anything from my library. There are a lot of articles around the web and all of them tells me how to hide the VisualStudio warning, the thing is problem persists. How can I use something like vector or shared_ptr if I cannot export them safely?

    Like this:

    class MY_API MyClass
    {
    public:
        MyClass();
    private:
        std::vector<int> indices;
    };

    where MY_API is __declspec(dllimport/dllexport) thingy. How do you tackle this problem?

  • Dave AllanDave Allan

    This is beautiful. Thank you so much for sharing. I finally get it!!

  • flamiflami flami

    A great talk!! Angel I appreciate the crisp and detailed explanation. 

Remove this comment

Remove this thread

close

Comments Closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums,
or Contact Us and let us know.