I’m sure typename and typedef are not new to anyone who has used C++, but I still couldn’t understand the following code when I saw it.
|
|
It stands to reason that typedef is not generally used to define an alias for a type, as follows.
|
|
Having defined an int with the alias SpeedType, I can then use it like this.
But what does typedef followed by typename mean, and isn’t typename used to define template parameters? Let’s summarize the usage of typedef & typename separately.
typedef
First, let’s look at a few common uses of typedef.
Aliases for types with specific meanings
I’ve already covered this above, but it’s defining an alias for a type, not just a simple macro substitution, and can also be used to declare multiple objects of the pointer type at the same time.
For example.
We wanted to declare both pa and pb as strings, but we could only declare one of them successfully.
But we can declare both of them using typedef.
Aliasing structs
When declaring variables, you need to bring struct, i.e. use it like the following.
Used to define platform-independent types
For example, define a floating point type called REAL, on target platform 1, and let it represent the highest precision type as follows.
|
|
On platform 2, which does not support long double, it is modified as follows.
|
|
When cross-platform, just change the typedef itself, without making any changes to the rest of the source code.
typename
The typename keyword is used to introduce a template parameter. This keyword is used to indicate that the non-dependent names in the template declaration (or definition) are type names, not variable names.
typename in this context means that T is a type. Without it, ambiguity can arise in some cases, such as the following.
The author wants to define a pointer iter
that points to an iterator
of type contained in the class scope T
. It is possible that there is such a structure containing the type iterator
.
Then foo<ContainsAType>();
when used this way does tell iter
is a pointer of type ContainsAType::iterator
. But T::iterator
can actually be of any of the following three types.
- Static data members
- Static member functions
- Nested types
So if it is a case like the following.
Then T::iterator * iter;
is instantiated by the compiler as ContainsAnotherType::iterator * iter;
and becomes a static data member multiplied by iter, so that the compiler will not find the definition of another variable iter
. So to avoid this ambiguity, we add typename to indicate that T::iterator
must be a type.
Drawing conclusions
Let’s go back to the example at the beginning, for vector::size_type
, we can know that
vector::size_type
is a nested type definition of vector
, which is actually equivalent to the size_t
type.
|
|
The real face of this example, then, is that typedef
creates an alias for the existent type, and typename
tells the compiler that std::vector<T>::size_type
is a type and not a member.
An example
Well, after reading the above example you should have fully understood the essence of typedef & typename, let’s explain an example of using a template to implement a loop similar to the one below.
First we need a loop template.
|
|
As you can see here, the templates, both res_type and type, are modified with typename to indicate that they are types, and then typedef to indicate that an alias is defined for the type.
When defining the loop template again, there is a convention that it must provide a static data member, cond_value, and two subtype definitions, res_type and next_type.
- cond_value represents the condition of the loop (true or false), indicating that it is directly a static data member of definite bool type, unmodified by typename.
- res_type represents the state when the loop is exited, and is a type rather than a member.
- next_type represents the state when the following loop is executed once, and is a type rather than a member.
WhileLoop uses specialization to decide whether to take the recursive branch or exit the loop branch.
We then define a template to represent the value.
The value can be obtained by value, and the value_type is the type of the value.
|
|
The above template enables the result of While<Sum<10>::type>::type::value
1 to 10. In fact, the result of the 1 to 10 operation is achieved by a circular expansion of types.
Reference
https://www.luozhiyun.com/archives/742