Why does the C++ standard define two phase lookup for templates? Couldn't non dependent declarations and definitions' lookups be deferred to the instantiation stage as well?
They could. This is the way most early implementations of templates
worked, and is still the way the Microsoft compiler worked. It was felt
(in the committee) that this was too error prone; it made it too easy to
accidentally hijack a name, with the instantiation in one translation
unit picking up a local name, rather than the desired global symbol. (A
typical translation unit will consist of a sequence of #includes,
declaring the names that everyone should see, followed by implementation
code. At the point of instantiation, everything preceding the point of
instantation is visible, including implementation code.)
The final decision was to classify the symbols in a template into two
categories: dependent and non-dependent, and to insist that the
non-dependent symbols be resolved at the point of definition of the
template, to reduce the risk of them accidentally being bound to some
local implementation symbols. Coupled with the requirement to specify
typename and template when appropriate for dependent symbols, this
also allows parsing and some error checking at the point of definition
of the template, rather than only when the template is instantiated.
This could be viewed as an application of separation of concerns.
At the first phase it just checks for correct syntax, and resolves non-dependent names, as explained here. At the second phase it does something more template specific, verifying if the calls are valid with the specific types. See this [answer] ( Two phase lookup - explanation needed)
Furthermore, if it would be done in only one phase, then it should be done every instantiation. This way is done only once.
If would be done only on the first instantiation, then it would be the same thing, only less structured.
Related
Suppose I have two translation units:
//A.cpp
class X
{
};
//B.cpp
class X
{
int i;
};
Is the above program well-formed?
If not, no further questions. If the answer is yes, the program is well-formed (ignore the absence of main), then the second question. What if there is a function with the same name in those?
//A.cpp
class X
{
void f(){}
};
//B.cpp
class X
{
int i;
void f(){}
};
Would this be a problem for the linker as it would see &X::f in both object files? Are anonymous namespaces a must in such a situation?
Is the above program well-formed?
No. It violates the One-Definition Rule:
[basic.def.odr]
There can be more than one definition of a
class type ([class]),
...
in a program provided that each definition appears in a different translation unit and the definitions satisfy the following requirements.
Given such an entity D defined in more than one translation unit, for all definitions of D, or, if D is an unnamed enumeration, for all definitions of D that are reachable at any given program point, the following requirements shall be satisfied.
...
Each such definition shall consist of the same sequence of tokens, where the definition of a closure type is ...
...
Are anonymous namespaces a must in such a situation?
If you need different class definitions, they must be separate types. A uniquely named namespace is one option, and an anonymous namespace is a guaranteed way to get a unique (to the translation unit) namespace.
Short version
Well, no... C++ bases on assumption that every name in a namespace is unique. If you break that assumption you have 0 guarantee it will work.
For example if you have methods with the same name in two translation units (*.o files). Linker wont know which one to use for given call so it will just return an error.
Long version
... but actually yes!
There is actually quite a few situation when you could get away with classes/methods with the same name.
Do not actually use any of these tricks in your programs! Compilers are free to do pretty much anything if they think it will optimize the resulting program so any of the assumption bellow may break.
Classes are the easiest. Let's take some class with only non-static members and no functions. Such a thing don't even leave any trace in the compiled program. Classes/structs are only tools for a programmer to organize data so there is no need to deal with memory pools and offsets.
So basically if you have two classes with the same name in different compilation units, it should work. After the compiler is done with them, they will consist of just a few instruction of how much to move a pointer in memory to access a specific field.
There is hardly anything here that would confuse the linker.
Functions and variables (including static class variables) are more tricky because compiler often creates symbols for them in the *.o file. If you're lucky linker may ignore them if such a function/variable is not used but I wouldn't even count on that.
There are ways, though, to omit creating symbols for them. Static global elements or ones in anonymous namespaces are not visible outside their translation units so linker shouldn't complain on them. Also, inlined functions don't exist as separate entities so they also don't have symbols, which is especially relevant here because functions defined inside classes are inlined by default.
If there is no symbol, linker won't see a conflict and everything should compile.
Templates are also using some dirty tricks because they are compiled on demand in each compilation unit that uses them but they end up as a single copy in the final programs. I don't think this is the same case as multiple different things with the same name so let's drop the topic.
In conclusion, if your classes don't have static members and they do not define functions outside of their bodies, it may be possible to have two classes with the same name as long as you don't include them in the same file.
This is extremely fragile, though. Even if it works right now, a new version of the compiler may have some fix/optimization/change that would broke such program.
Let alone the fact that includes tends to be pretty interwoven in bigger projects so there is decent chance that at some point you will need to include both files in the same place.
I'm getting a strange behavior which I don't understand. So I have two different classes with the same name defined in two different cpp files. I understand that this will not cause any error during the compilation of the translation units as they don't know about each other. But shouldn't the linker throw some error when it links these files together?
You're thinking of the one definition rule. I'm quoting from there (boldface is emphasis of my choosing, not a part of the original document).
Your understanding would be correct--it's illegal to define the same function in multiple compilation units:
One and only one definition of every non-inline function or variable that is odr-used (see below) is required to appear in the entire program (including any standard and user-defined libraries). The compiler is not required to diagnose this violation, but the behavior of the program that violates it is undefined.
However, this isn't the case for classes, which can be defined multiple times (up to once in each compilation unit), as long as the definitions are all identical. If they are identical, then you can safely pass instances of that class from one compilation unit to another, since all compilation units have compatible, identical definitions with compatible sizes and memory layouts.
Only one definition of any variable, function, class type, enumeration type, concept (since C++20) or template is allowed in any one translation unit (some of these may have multiple declarations, but only one definition is allowed).
...
There can be more than one definition in a program, as long as each definition appears in a different translation unit, of each of the following: class type, enumeration type, inline function with external linkage inline variable with external linkage (since C++17), class template, non-static function template, static data member of a class template, member function of a class template, partial template specialization, concept, (since C++20) as long as all of the following is true:
each definition consists of the same sequence of tokens (typically, appears in the same header file)
name lookup from within each definition finds the same entities (after overload-resolution), except that constants with internal or no linkage may refer to different objects as long as they are not ODR-used and have the same values in every definition.
overloaded operators, including conversion, allocation, and deallocation functions refer to the same function from each definition (unless referring to one defined within the definition)
the language linkage is the same (e.g. the include file isn't inside an extern "C" block)
the three rules above apply to every default argument used in each definition
if the definition is for a class with an implicitly-declared constructor, every translation unit where it is odr-used must call the same constructor for the base and members
if the definition is for a template, then all these requirements apply to both names at the point of definition and dependent names at the point of instantiation
If all these requirements are satisfied, the program behaves as if there is only one definition in the entire program. Otherwise, the behavior is undefined.
The bullet points are a fancy and highly precise way of specifying that the definitions must be the same, in letter and in effective result.
The one-definition rule specifically permits this, as long as those definitions are completely, unadulteratedly, identical.
And I do mean absolutely identical. Even if you swap the token struct for the token class, in a case where it would otherwise not matter, your program has undefined behaviour.
And it's for good reason: typically we define classes in headers, and we typically include such headers into multiple translation units; it would be very awkward if this were not allowed.
The same applies to inline function definitions for the same reason.
As for why you don't get an error: well, like I said, undefined behaviour. It would technically be possible for the toolchain to diagnose this, but since multiple class definitions with the same name are a totally commonplace thing to do (per above), it's arguably a waste of time to come up with what would be quite complicated logic for the linker of all things to try to diagnose "accidents". Ultimately, as with many things in this language, it's left up to you to try to get it right.
I am helping with some effort of improving the build speed of a big c++ project.
One of the issues is that different set of includes my result in different execution code if template specializations are involved - based on if they are visible or not.
I am trying to create a practice (rule) that will prevent such issues.
The rule I am having right now is:
Template specialization has to be either in the same header file with the template or in the header of one of the types involved in the specialization.
This seems to me that it will be sufficient to make sure that if specialization is usable - it will be always visible whatever subset of headers are included.
My question is - do you see any flaw in such rule?
When some C++ entity, such as a structure, class, or function, is declared as a template, then the definitions provided for said entities are solely blue-prints which must be instantiated.
Due to the fact that a template entity must be defined when it is declared (which is commonly header files) I have the conception, which I try to convince myself as wrong, that when after a template has been instantiated it will be inlined by the compiler. I would like to ask if this is so?
The answer for this question raises my suspicion when I read the the paragraph:
"Templates can lead to slower compile-times and possibly larger
executable, especially with older compilers."
Slower compile-times are clear as template must be instantiated but why "possibly larger executables"? In what ways should this be interpreted? Should I interpret this as 'many functions are inlined' or 'the executable's size increases if there are many template instantiations, that is the same template is instantiated with a lot of different types, which causes several copies of the same entity to be there'?
In the latter case, does a larger executable size cause the software to run more slowly seeing that more code must be loaded into memory which will in turn cause expensive paging?
Also, as these questions are also somewhat compiler dependent I am interested in the Visual C++ compiler. Generalised answers concerning what most compilers do give a good insight as well.
Thank you in advance.
Due to the fact that a template entity must be defined when it is declared (which is commonly header files)
Not true. You can declare and define template classes, methods and functions separately, just like you can other classes, methods and functions.
I have the conception, which I try to convince myself as wrong, that when after a template has been instantiated it will be inlined by the compiler. I would like to ask if this is so?
Some of it may be, or all of it, or none of it. The compiler will do what it deems is best.
Slower compile-times are clear as template must be instantiated but why "possibly larger executables"? In what ways should this be interpreted?
It could be interpreted a number of ways. In the same way that a bottle of Asprin contains the warning "may induce <insert side-effects here>".
Should I interpret this as 'many functions are inlined' or 'the executable's size increases if there are many template instantiations, that is the same template is instantiated with a lot of different types, which causes several copies of the same entity to be there'?
You won't have several copies of the same entity - the compiler suite is obliged to see to that. Even if methods are inline, the address of the method will:
always exist, and
be the same address when referenced by multiple compilation units.
What you may find is that you start creating more types than you intended. For example std::vector<int> is a completely different type to std::vector<double>. foo<X>() is a different function to foo<Y>(). The number of types and function definitions in your program can grow quickly.
In the latter case, does a larger executable size cause the software to run more slowly seeing that more code must be loaded into memory which will in turn cause expensive paging?
Excessive paging, probably not. Excessive cache misses, quite possibly. Often, optimising for smaller code is a good strategy for achieving good performance (under certain circumstances such as when there is little data being accessed and it's all in-cache).
Whether they are inlined is always up to the compiler. Non-inlined template instantiations are shared for all similar instantiations.
So a lot of translation units all wanting to make a Foo<int> will share the Foo instantiation. Obviously if Foo<int> is a function, and the compiler decides in each case to inline it then the code is repeated. However the choice to inline is because the optimization of doing so seems highly likely to be superior to a function call.
Technically there could be a corner case where a template causes slower execution. I work on software which has super tight inner loops for which we do a lot of performance measurements. We use a number of template functions and classes and it has yet to show up a degradation compared to writing the code by hand.
I can't be certain but I think you'd have to have a situation where the template:
- generated non-inlined code
- did so for multiple instantiations
- could have been one hand-written function
- hand-written function incurs no run-time penalty for being one function (ie: no implicit conversions involving runtime checks)
Then it's possible that you have a case where the single-handwritten-function fits within the CPU's instruction cache but the multiple template instantiations do not.
What does it mean that compiler is using two phase lookup in order to compile template class?
Templates are compiled (at least) twice:
Without Instantiation the template code itself is checked for syntax.
Eg: Any syntax errors such as ; etc.
At the time of instantiation(when the exact type is known), the template code is checked again to ensure all calls are valid for that particular type.
Eg: The template might in turn call to functions which might not be present for that particular type.
This is called as Two Phase Lookup.