The impact of virtual on the use of member of class template - c++

I (vaguely) know that a template is not instantiated if it is not used. For example, the following code will compile fine even though T::type doesn't make sense when T = int.
template<typename T>
struct A
{
void f() { using type = typename T::type; }
};
A<int> a; //ok
It compiles because f() is not used, so it is not instantiated — thus the validity ofT::type remains unchecked. It doesn't matter if some other member function g() calls f().
template<typename T>
struct A
{
void f() { using type = typename T::type; }
void g() { f(); } //Is f() still unused?
};
A<int> a; //ok
This also compile fines. But here I realize the vagueness in my understanding of the definition of "use". I ask:
Is f() still unused? How exactly?
I can clearly see it being used inside g(). But then I thought since g() is not used, f() is not used either, from instantiation point of view. That seems reasonable enough. so far.
However if I add virtual keyword to g(), it doesn't compile:
template<typename T>
struct A
{
void f() { using type = typename T::type; }
virtual void g() { f(); } //Now f() is used? How exactly?
};
A<int> a; //error
It results in compilation error because now it attempts to instantiate f(). I don't understand this behavior.
Could anybody explain this? Especially the impact of virtual keyword on the definition of "use" of member of class template.

A quick look at 3.2 [basic.def.odr] yields:
3/ [...] A virtual member function is odr-used if it is not pure. [...]
And I also found at 14.7.1 [temp.inst]:
10/ An implementation shall not implicitly instantiate a function template, a member template, a non-virtual member function, a member class, or a static data member of a class template that does not require instantiation. It is unspecified whether or not an implementation implicitly instantiates a virtual member function of a class template if the virtual member function would not otherwise be instantiated. (emphasis mine)
So... I would say it is likely that a virtual method will always be instantiated.
In pragmatic terms, I would expect a compiler to instantiate the virtual table of a template class when it instantiates the class; and thus immediately instantiate all virtual member functions of this class (so it can references those from the virtual table).

Related

C++ class member function definition missing in object file and all fdump results [duplicate]

I just started to understand some template basics. Actually, until now I just accepted it as a fact, but I dont really understand the reason why this is broken:
template <typename T,bool hasFoo>
struct Broken {
void foobar(){
if (hasFoo){T::foo();}
else { std::cout << "BROKEN" << std::endl;}
}
};
int main(){
Broken<int,false> t;
t.foobar();
}
while this works:
template <typename T>
struct Works {
void foo(){T::foo();}
void bar(){std::cout << "WORKS" << std::endl;}
};
int main(){
Works<int> t;
t.bar();
}
Somehow it is obvious, but I just want to make sure that I am not missing something:
Does this work, because if the function Works<int>::foo() is never called, it simply does not get instantiated?
PS: To avoid misunderstandings: I know, why Broken is broken and I recently had a question related to this where I got good answers, however after that I thought that also Works<int> should not compile until I accidentally passed a "wrong" template parameter and was surprised that it did compile.
if the function Works::foo() is never called, it simply does not get instantiated?
Yes, a non-virtual member function of class template won't be instantiated until it's required.
From the standard, §12.8.1/10 Implicit instantiation [temp.inst]:
(emphasis mine)
An implementation shall not implicitly instantiate a function
template, a variable template, a member template, a non-virtual
member function, a member class, a static data member of a class
template, or a substatement of a constexpr if statement ([stmt.if]),
unless such instantiation is required.
To answer the question in your title, no, it does not need to be called to be instantiated.
This code does not compile, yet foo is never called.
template <typename T>
struct Works {
void foo(){T::foo();}
void bar(){}
};
// this requires foo being instantiated because it may be called from
// elsewhere - the compiler cannot know.
template Works<int>;
int main(){
Works<int> t;
t.bar();
}
live: https://godbolt.org/g/u4frVZ
This is why the standard says it is not instantiated unless it requires instantiation and the rules for that are more complicated than whether it is called.

A confusion about explicit specialization for member of class template

template<class T> struct A {
struct B { };
template<class U> struct C {
void show();
};
};
template<>
template<>
void A<int>::C<int>::show(){ //#1
}
int main(){
}
Consider the above code, At #1, it's an explicit specialization definition for member of member class template. Some rules will be applied to it as the following specified:
temp.expl.spec#5
A member of an explicitly specialized class is not implicitly instantiated from the member declaration of the class template; instead, the member of the class template specialization shall itself be explicitly defined if its definition is required. In this case, the definition of the class template explicit specialization shall be in scope at the point at which the member is defined. The definition of an explicitly specialized class is unrelated to the definition of a generated specialization. That is, its members need not have the same names, types, etc. as the members of a generated specialization. Members of an explicitly specialized class template are defined in the same manner as members of normal classes, and not using the template<> syntax. The same is true when defining a member of an explicitly specialized member class. However, template<> is used in defining a member of an explicitly specialized member class template that is specialized as a class template.
Firstly, what's explicitly specialized class? Does it refer to the entity which has explicit specialization declaration? It seems to it doesn't mean it, please look at the example in Explicitly specialized class part
template<> template<> class A<int>::B<double>;
According to that example, A<int> within the explicit specialization for member can be called a explicitly specialized class. So, In my first example A<int> and C<int> are all explicitly specialized class? I'm not sure. I feel the phrase explicitly specialized class is not clear in this section.
Please note the emphasized part, it means the enclosing class template explicit specialization shall appear in the same scope as that of explicit specialization definition for its member. The member is defined in global scope but there's no any explicit specialization definition for A<int> or C<int> that appears in the global scope. How to interpret this?
By the way, as a opposite example:
template<class T> struct A {
struct B { };
template<class U> struct C {
void show();
};
};
template<>
template<typename U>
struct A<int>::C{ //#2
void show();
};
template<>
template<typename U>
void A<int>::C<U>::show(){ //#3
}
int main(){
}
why such code is required an explicit specialization for class template C before #3, what's the difference between such two examples?
Explicitly specialized class
The phrase "explicitly specialized class" is unclear in this section,
temp.expl.spec#15
A member or a member template may be nested within many enclosing class templates. In an explicit specialization for such a member, the member declaration shall be preceded by a template<> for each enclosing class template that is explicitly specialized.
[ Example:
template<class T1> class A {
template<class T2> class B {
void mf();
};
};
template<> template<> class A<int>::B<double>;
template<> template<> void A<char>::B<char>::mf();
— end example ]
what's the explicitly specialized class mean, Is it refer to an entity that have a explicit specialization declaration or something others? It seems to no explicit specialization for A<int> in the above example.
There is no confusion there, you have to parse those statements (C++ and English) according to their grammatical structure. Source code is description of program in language understandable for humans. Programming language is a tool of human cooperation.
CWG529 removed need to understand intuitively by changing wording to explain order and content of template-ids.
Here you declared template of class A with template parameter T, which contains class B and a nested declaration of template class C with template parameter U, which contains a method show():
template<class T> struct A {
struct B { };
template<class U> struct C {
void show();
};
};
Here you declared, that for explicitly specialized template class A (which required to have it declared first) with T = int that there is a template class C which contains method show()
template<>
template<typename U>
struct A<int>::C{ //#2
void show();
};
This declaration doesn't contradict previous one, but because it's a specialization of class A, it may expand it! You can do this:
template<>
template<typename U>
struct A<int>::C{ //#4
void hide();
};
Which means that for any A with T=int, there is a template class C that got member hide(). But other A's will have template class C with member show(). What previous statement did that it removed any doubts about content of C for this A's specialization.
Now this only defines member function show() for all C's contained in A<int>:
template<>
template<typename U>
void A<int>::C<U>::show(){ //#3
}
You don't have an explicit specialization of C here, which is an enclosing class for show(). the memeber id show() is preceded by an unspecialized template-id template<typename U> ... C<U>. There is only a definition of member function but it requires a visible declaration of that template C - the #2 part. The visibility may be attained by various means and "the scope" mentioned is generalized description of it.
Omitting part #2 would be a semantic equivalent of writing:
class C;
void C::show() { // ill-formed - C is an incomplete type.
}
We would know that all of A's contain some class C, but we don't have a complete definition for that particular C in specialized A<int> (and it may be different).
This statement actually states that specialization C<int>nested in specialization A<int> contains show()
template<>
template<>
void A<int>::C<int>::show(){ //#1
}
Any possibility of contradiction, ambiguity or uncertainty (aside from undefined behavior) are leading to ill-formed code and rules are meant to form the framework of limitations against which the code should be checked. With absence of #2, the #3 at some point could be followed by #4, then the #3 statement would become illegal and thus it is deemed as such. #2 and #4 at same time would be two definitions of same thing which also leads either to ill-formed code if they are present in same unit, or they would lead to undefined behavior if they are present in separate units within program.

Ambiguous when two superclasses have a member function with the same name, but different signatures

struct A {
void f(int x) {}
};
struct B {
template<typename T> void f(T x) {}
};
struct C : public A, public B {};
struct D {
void f(int x){}
template<typename T> void f(T x) {}
};
int main(int argc, char **argv) {
C c;
c.f<int>(3);
D d;
d.f<int>(3);
}
What is the reason for which calling d.f is fine, but c.f gives
error: request for member ‘f’ is ambiguous
error: candidates are: template<class T> void B::f(T)
error: void A::f(int)
The first part is due to member name lookup, that's why it fails.
I would refer you to: 10.2/2 Member name lookup
The following steps define the result of name lookup in a class scope,
C. First, every declaration for the name in the class and in each of
its base class sub-objects is considered. A member name f in one
sub-object B hides a member name f in a sub-object A if A is a base
class sub-object of B. Any declarations that are so hidden are
eliminated from consideration. Each of these declarations that was
introduced by a using-declaration is considered to be from each
sub-object of C that is of the type containing the declaration
designated by the using-declaration.
If the resulting set of declarations are not all from sub-objects of
the same type, or the set has a nonstatic member and includes members
from distinct sub-objects, there is an ambiguity and the program is
ill-formed. Otherwise that set is the result of the lookup.
Now, for the matter with template functions.
As per 13.3.1/7 Candidate functions and argument list
In each case where a candidate is a function template, candidate
function template specializations are generated using template
argument deduction (14.8.3, 14.8.2). Those candidates are then handled
as candidate functions in the usual way. A given name can refer to one
or more function templates and also to a set of overloaded
non-template functions. In such a case, the candidate functions
generated from each function template are combined with the set of
non-template candidate functions.
And if you continue reading 13.3.3/1 Best viable function
F1 is considered to be a better function, if:
F1 is a non-template function and F2 is a function template
specialization
That's why the following snippet compiles and runs the non-template function without error:
D c;
c.f(1);
I believe the compiler prefers A::f (non-template function) over B::f for no reason.
This seems to be a compiler implementation bug more than a implementation dependent detail.
If you add following line, then compilation goes fine and the correct function B::f<> is selected:
struct C : public A, public B {
using A::f; // optional
using B::f;
};
[Funny part is that until the ::f are not brought into the scope of C, they are treated as alien functions.]
A compiler doesn't know which method to call from the C class because templated method will be transormed in void f(int) in case of int type so you have two methods with the same name and same arguments but members of different parent classes.
template<typename T> void f(T x) {}
or
void f(int)
try this:
c.B::f<int>(3);
or this for the A class:
c.A::f(3);
Consider this simpler example:
struct A{
void f(int x){}
};
struct B{
void f(float t){}
};
struct C:public A,public B{
};
struct D{
void f(float n){}
void f(int n){}
};
int main(){
C c;
c.f(3);
D d;
d.f(3);
}
In this example, same as yours, D compiles but C does not.
If a class is a derived one, member lookup mechanism behaves different. It checks each base class and merges them: In the case of C; Each base class matches the lookup ( A::f(int) and B::f(float) ). Upon merging them C decides they are ambiguous.
For the case class D: int version is selected instead of float because parameter is an integer.
What is probably happening is that the template instantiation is happening separately for class A and B, thus ending in two void f(int) functions.
This does not happen in D since there the compiler knows about the void f(int) function as a specialization and therefore does not specialize T for int.

Why does function calls to templatized base classes not work?

Consider the following example:
template <typename T>
class A {
public:
void f() {
cout << "A::f()\n";
}
};
template<>
class A<int> {
};
template<typename T>
class B: public A<T> {
public:
void g() {
cout << "B::g()\n";
A<T>::f();
}
};
int main() {
B<int> b; // (1)
b.g(); // (2)
return 0;
}
Obviously the call to A::f() inside B::g() will fail for int template type. My question is at what point does the call fail? At (1) or (2)? I thought it should be (1) because at that point the compiler creates a new class with the template type int and compiles it. That compilation should fail in f() correct?
It will fail at (2), and this is guaranteed by the standard. In section 14.7.1/1, it says instantiating a template class does not instantiate it's members definitions. That will only happen once the member is used.
If you remove (2) from the code, it will compile.
14.7.1/1 excerpt:
The implicit instantiation of a class template specialization causes the implicit
instantiation of the declarations, but not of the definitions or default arguments, of the class member functions, member classes, static data members and member templates; and it causes the implicit instantiation of the definitions of member anonymous unions.
Emphasis mine.
Visual Studio's diagnosis is misleading. It will say see reference to class template instantiation 'B<T>' being compiled. What it means is not "I'm failing at the instantiation of B<T>", but "I'm failing at instantiating a member of the class B<T>"
It fails at 2). Member function of templates are instantiated when called.
More precisely: When a class template is instantiated, the declaration of its member functions are instantiated, but not their definition. The definition is instantiated when the function is used.

Is this code legal in C++

I just found that when it comes to templates this code compiles in g++ 3.4.2 and works unless m() is not called:
template <typename T>
class C
{
T e;
public:
C(): e(0) {};
void m()
{
e = 0;
};
};
Now one may create and use instance
C<const int> c;
Until c.m() is not called there are no compile errors but is this legal?
Yes, this is legal. The template specification is that until a method is instantiated, it doesn't exist and therefor is not checked by the compiler. Here's the relevant bit from the spec:
14.7.1 - Implicit instantiation
-9- An implementation shall not implicitly instantiate a function
template, a member template, a
non-virtual member function, a member
class or a static data member of a
class template that does not require
instantiation.