First, take a look at the following code:
template<typename T>
std: :vector<T>& arrayRotate(const std: :vector<T>& src)
{
std: :vector<T> dst(src.size());
for (std: :vector<T>::iterator iter = src.begin(); src.end() ! = iter; iter++) { dst.push_back(*iter); }return dst;
}
Copy the code
If you can see what’s wrong at a glance, you don’t have to look any further. You’re already half an expert on C++ template. (laughter)
For (STD ::vector
::iterator iter = src.begin(); src.end() ! = iter; Iter++) is missing one line; If you look closely at the Code IntelliSense for each token, you will find that
iter is displayed on the word iter. The problem becomes clear: STD ::vector
::iterator is not a type that the compiler can determine. The solution is simple, simply add typename to indicate that this is a typename:
for (typename std: :vector<T>::const_iterator iter = src.begin(); src.end() ! = iter; iter++)Copy the code
Compile again, problem solved. (C++ Primer states that it is not possible to use class instead of typename[3], but I have tested in VC2019 that it is possible to use class instead of typename, probably because Microsoft did not use typename in early C++. This may not work in other compilers, so you should also follow Stanley’s advice about using typename only.)
So let’s take a look at one of the more overlooked issues in this C++ Template: the typename keyword.
1 keywordtypename
Look at this example:
template <typename T>
class SomeClass {
typename T::SubType * ptr;
}
Copy the code
Typename is used for the same purpose as STD :: Vector
::iterator in the problematic program at the beginning of this article. Typename is used to show that an identifier inside a template can be a type. SubType is a type defined inside class T. Thus, PTR is a pointer to T::SubType. If typename is not used, SubType is treated as a static member, and it is resolved to a specific variable or object, so T::SubType * PTR is treated as the product of the static member SubType and PTR of class T [1].
2 .template
and->template
Look at this example:
template <int N>
void printBitset (std: :bitset<N> const& bs)
{
std: :cout << bs.template to_string<char, char_traits<char>, allocator<char> > (); }Copy the code
Basic_string = basic_string; basic_string = basic_string; basic_string = basic_string; basic_string = basic_string
template<
class CharT = char.class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>
> std::basic_string<CharT,Traits,Allocator>
to_string(CharT zero = CharT('0'), CharT one = CharT('1')) const;
Copy the code
So why not just call bs.to_string instead of inserting a weird.template declaration? The reason for this is that the passed parameter bs is constructed depending on the template parameter N. Without this declaration, the compiler will not adjust the less-than sign (<) that follows is not the mathematical less-than sign, but rather the template is the starting symbol [1] for the parameter list.
Therefore, it is not difficult to conclude that we need to use. Template or ->template inside the template only if there are objects that depend on template parameters in the front
3. Causes of ambiguity
In fact, as mentioned earlier, the main reason for the ambiguity is that these are related to template parameters. After the introduction of templates, we can divide C++ names into two types: Dependent names and non-dependent names[2]. Non-dependent names are completely independent names, and dependent names are names that are affected by template parameters. You can’t really determine the meaning of these names until the template is visualized. (Instantiation might be used in some places, but I prefer visualization to distinguish it from class instantiation.) So some extra syntax is needed to make sure the compiler works correctly.
4 Processing methods in other languages
This rule doesn’t feel very smart when you look at it, and it was rumored that C++ 11 was supposed to fix this [2], but it doesn’t seem to have changed much. Let’s look at how Java, which also has the Template syntax, handles this problem.
class Pair<T>
{
private T value;
private SubType subObject;
public Pair(T val) {
value = val;
subObject = new SubType();
subObject.subValue = 1000;
}
public class SubType {
public int subValue;
}
public SubType getSubObject(a) {
returnsubObject; }}public class Main {
public static void main(String[] args) {
Pair<Integer> pair = new Pair<>(Awesome!);
Pair<Integer>.SubType subObject = pair.getSubObject();
intresult = subObject.subValue; System.out.println(result); }}Copy the code
There is no typename keyword like typename in C++. Compile, run, and get the result:
1000
Copy the code
It seems that Java doesn’t have as many constraints as C++, but that’s really because there’s no such thing as Template specialization in Java. Well, that’s a big topic for another time.
Voiceover: Why is the title Orz again
References: [1] C++ Templates, David Vandevoorde [Germany]Nicolai m. Josuttis, translated by Chen wezhu, posts and telecommunications press, 2013 [2] A Description of the C++ typename keyword, Evan Driscoll, pages.cs.wisc.edu/~driscoll/t… [3] C++ Primer 5e, Stanley b. Lippman, publishing house of electronics industry, 2013.9