C++ 11: Alias and Alias Template

Discussion in 'C++' started by BiplabKamal, Feb 25, 2016.

  1. When the name of something or some person is big and we are bored to call the same long name again and again we try to find a short name easy to call in place of original name. This is like a nickname. In C++11 programming, we use aliasing to create shorter type name for an existing longer type name. This can be also be done using 'typedef' keyword. To understand the usage of typedef and alias let us take an example. In the following code the type name for variable itr1 and itr2 is long enough to irritate the programmer if he needs to type the type names multiple times. So the need of a short name for the long type name is really necessary.
    Code:
    vector<int> MyIntVector;
    std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int>>> itr1 = MyIntVector.begin();
    std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int>>> itr2 = MyIntVector.end();
    
    We can define a new type with shorter and simpler type name to type in place of above type name using 'typedef' keyword already available in C++ even before C++11 is released. Using 'typedef' we can write the above code as shown below -
    Code:
    vector<int> MyIntVector;
    typedef std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int>>> ItrForIntVector;
    ItrForIntVector itr1 = MyIntVector.begin();
    ItrForIntVector itr2 = MyIntVector.end();
    
    C++11 added one more new way of creating nickname called alias for an existing type name. For this a new keyword 'using' is introduced. Using 'using' keyword we can rewrite the above code as:
    Code:
    vector<int> MyIntVector;
    using ItrForIntVector = std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int>>>;
    ItrForIntVector itr1 = MyIntVector.begin();
    ItrForIntVector itr2 = MyIntVector.end();
    
    You might be noticing that 'typedef ' decleration and alias decleration ('using') both create a new name for an existing type and they are doing the same thing. Then why do we need 'using' keyword when we have 'typedef' key word. Yes they are almost similar. Both typedef and aliasing create new type names for already existing types. They don't create new types but new names for existing types. But there is a subtle difference. Look into following code of declaring function pointer -
    Code:
    // Creating an alias 'funcptr' which is a synonym for a pointer to function which takes an int and return an int
    using funcptr = int(*)(int);// valid in C++11
    typedef int(*funcptr)(int); // valid in C++98
    funcptr fptr = [](int i) {return i*i;}; //valid in C++11: assigning a lamda expression to the function pointer object
    
    Don't you think that alias declaration is easier than typedef in case of function pointer? I think aliasing is more readable and easy to handle. You might be bothering whether that reason is enough for having a new keyword or not. Certainly not. Actually there is more to expect from aliasing. And that is alias template i. e. you can declare an alias templated. Alias template is main motivation of aliasing ('using' key word). typedef can not be templated. Folowing decleration and assignment uses templated alias.
    Code:
    template<typename T>
    using func = T (*)(T);
    func<int> fptr = [](int i) {return i*i;};
    
    The syntax of alias declaration is shown below:
    1. using identifier = type-id;
    2. template < template-parameter-list >

      using identifier = type-id;

      Where identifier is the new name assigned, type-id is the existing type and template-parameter-list is the list of template parameters.
    Alias template gives programmers a better and straight mechanism to define things which had to be hacked together with typedefs nested inside templated classes/structs. Let us look into another example of alias template. We will define a synonym for a linked list. Without alias declaration we can do this by typedef as shown below:
    Code:
    template <typename T>
    struct MyList
    {
        typedef std::list<T> mytype;
    };
    MyList<int>::mytype lst;//Client code
    
    In the above code MyList<T>::mytype is a synonym for std::list<T>. Here you are creating a templated type name indirectly with a nested typedef inside a struct.

    Now if you want to declare a member variable of a templated class of the templated type created in the above code the 'typenmae' keyword is required as shown in the class below:
    Code:
    template <typename T>
    class MyClass
    {
    private:
        [b] //MyClass<T> contains a data member of type std::list<T> [/b]
        typename MyList<T>::mytype lst;
    };
    
    Here MyList<T>::mytype is a type that is dependent on template parameter(T). So MyList<T>::mytype is a dependent type and dependent type name has to be preceded by typename keyword.

    But using C++11 alias declaration, the code will look like:
    Code:
    [b]//MyList<T> is a synonym for std::list<T>[/b]
    template <typename T>
    using MyList = std::list<T>;
    MyList<int> intlst; //Client code
    //Declaring a member of a class of type std::list<T> is straight forward
    template <typename T>
    class MyClass
    {
    private:
        MyList<T> lst; [b]//No typename and no ::mytype[/b]
    };
    
    Here MyList<T> may look like a dependent type but it is not. MyList<T>::mytype and MyList<T> are not same. MyList<T> type exist independently but MyList<T>::mytype does not exist without MyList<T>. So ::mytype is dependent on the type of T. It is possible that MyList<T>::mytype may not always be a type name or same type, it may be a data member also for some value of T. Confused? Suppose there is a specialization of the template struct MyList like:
    Code:
    class SomeClass;
    template <>
    struct MyList<SomeClass>
    {
        enum class SomeClassType{Type1, Type2,Type3};
        SomeClassType mytype;
    };
    
    The definition of the class MyList is different when the template parameter is of type SomeClass. In this case mytype is a data member and not a typedef. So mytype is dependent on template parameter. When compiler sees a dependent type it wants to confirm that it is a type by preceding it with typename keyword. On the other hand when the compiler sees an alias template type it always knows that it is a type.

    The template libraries in C++14 added alias versions of templated types for typedefs versions of C++11. One example is type_traits. C++11 it included transformation tools to transform types in the form of type traits declared in the header <type_traits>. For example:
    Code:
    std::remove_const<T>::type; //Results T from const T
    std::remove_reference<T>::type;// //Results T from T& and T&&
    std::add_lvalue_reference<int>::type; // Results T& from T
    
    Those are nested typedefs and are dependent types.

    C++14 added alias templates for those type traits. Following is equivalent code using alias template:
    Code:
        
    std::remove_const_t<T>; //Results T from const T
    std::remove_reference_t<T>;//Results T from T& and T&&
    std::add_lvalue_reference_t<T>; // Results T& from T
    
    Even if you don't have access to C++14 you may create those types using alias templates as shown below:
    Code:
    template< typename T >
    using remove_const_t = typename std::remove_const< T >::type; 
    template< typename T >
    using remove_reference_t = typename std::remove_reference< T >::type;
    template< typename T >
    using add_lvalue_reference_t = typename std::add_lvalue_reference< int >::type;
    
    Here is an example of using the alias template type traits remove_const_t<T>. It shows how the constness removal transform the type:
    Code:
    std::remove_const_t< const char > c1;     // type of c1 is char
    std::remove_const_t< const char* > c2;    // type of c2 is const char*
    std::remove_const_t< char* const > c3;    // type of c3 is char* 
    c1 = 'a';
    c2 = "abcd1234";
    c3 = new char[15];
    
    Alias and alias templates have made the developer's life easier when using STL. That does not mean you have to always create an alias for a long complex type name. The aim of aliasing is reducing the typing work and increase code readability. It is better to use alias than typedef to create a synonym for an existing type. Also new standard template library has used aliasing extensively. Alias may become a powerful tool when do generic programming.
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice