Prev: Is there any standard/guarantees for exception safety in STL operations?
Next: Is there any standard/guarantees for exception safety in STL operations?
From: Daniel Krügler on 26 Jul 2010 03:41 On 26 Jul., 16:13, DeMarcus <use_my_alias_h...(a)hotmail.com> wrote: > On 2010-07-26 01:56, DeMarcus wrote: > [..] > Ok, I realized I needed a bit compiler knowledge refresh. I found out > that it's not until A is instantiated that the error will show up. In your example that depends on the concrete implementation as shown in my previous posting. > Can you please confirm that the following is true? > > If I do the this > > struct A : Q<A> > { > }; > > the compiler will be able to deduce that A is a subclass of Q At which point? Not within the definition of Q<A>. > since the compiler compiles in two steps; first it goes through all the > declarations and sees everything is ok, then it goes through all the > definitions, and it will then find out that 'return T' is valid > according to the already processed declarations where it says that A > inherits from Q. (is there a paragraph in the standard confirming this?) No, see below. > Can you confirm that the following is correct as well? > > I extended the template to look like this. Note, I changed the fnc() > return type be of type T. > > template<typename T, class Base> > struct Q : Base > { > virtual T* fnc() { return new T; } > }; > > I extended A with some inheritance. > > struct A : Q<A, EmptyClass> > { > }; This is OK, because T can be incomplete, when the parser sees the declaration T* Q<>::fnc(); T is required to be complete within the definition of the function body, but that is not relevant for the compiler when parsing the definition of Q<A, EmptyClass>, where only the declaration of the members is needed. The role of the second template parameter is that of a base class, but a type must be complete to be used as a base class. I assume that EmptyClass is defined (not just declared), which makes it feasible for a base class. > struct B : Q<B, A> > { > }; > > The compiler will give me an error saying that B is not a covariant > return type of A (while it actually is). Is the compiler unable to > deduce the covariance because of the fact that it's only part of the > declaration step? In this example you are attempting to define a class Q<B, A>, that has a base class A, which again derives from Q<A, EmptyClass>. The base class is complete and effectively has a virtual function A* A<>::fnc(); Now when you attempt to instantiate Q<B, A> we have the same situation as we had in the example before: Within Q<B, A> B is an incomplete type. But since you are now overriding the base class, the standard requires that the return type is a derived class of the pointee used in the super class. Since B is incomplete within Q<B, A>, this declaration is ill-formed according to 10.3/6 (FCD): "If the return type of D::f differs from the return type of B::f, the class type in the return type of D::f shall be complete at the point of declaration of D::f or shall be the class type D." Note that it says: "at the point of the declaration of D::f", which is not satisfied in your example. > (would the compiler be able to find out, or do we break any rule by > doing that?) > > If I remove the keyword 'virtual' it will work because the compiler then > applies function overriding instead. > > Am I correct about how the compiler works? Not really ;-) HTH & Greetings from Bremen, Daniel Kr�gler -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Johannes Schaub (litb) on 26 Jul 2010 07:18 Daniel Krügler wrote: > On 26 Jul., 01:56, DeMarcus <use_my_alias_h...(a)hotmail.com> wrote: >> Hi, >> >> Consider this template. >> >> template<typename T> >> struct Q >> { >> virtual Q* fnc() { return new T; } >> >> }; >> >> If I now declare a variable like this >> >> Q<int> qi; >> >> I get the following from gcc 4.5.0. >> "error: cannot convert 'int*' to Q<int>*' in return". >> >> That seems perfectly correct. But now try this >> >> struct A : Q<int> >> { >> >> }; >> >> and it complies perfectly fine with gcc 4.5.0!!! That must be a bug, > right? > > This is not a bug, but an explicit freedom, the Standard > provides to implementors of templates: In contrast to > non-virtual functions, virtual functions may lead to > an immediate member instantiation, even, if not > used, see 14.7.1/9 (Both C++03 and FCD): > > "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." > This was precisely the paragraph i was arguing at http://groups.google.com.mt/group/comp.std.c++/browse_thread/thread/7a784b1aa5277c71 using the interpretation you use in this post :) Your answer back then was different: You seemed to say that it would not imply instantiating a definition. Did i misunderstand your statement back then? I still don't understand it, fwiw. The "It is unspecified ..." part seems totally redundant to me, because the ODR rule you quoted already requires instantiation for non-pure virtual functions, and does not require it for pure functions. What would be different if we would remove the "It is unspecified ...." sentence? -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Nikolay Ivchenkov on 26 Jul 2010 07:33 On 26 Jul, 21:46, James Kanze <james.ka...(a)gmail.com> wrote: > On Jul 26, 12:56 am, DeMarcus <use_my_alias_h...(a)hotmail.com> wrote: > > Consider this template. > > template<typename T> > > struct Q > > { > > virtual Q* fnc() { return new T; } > > }; > > If I now declare a variable like this > > Q<int> qi; > > I get the following from gcc 4.5.0. > > "error: cannot convert 'int*' to Q<int>*' in return". > > That seems perfectly correct. But now try this > > struct A : Q<int> > > { > > }; > > and it complies perfectly fine with gcc 4.5.0!!! That must be > > a bug, right? > > No. The code is perfectly legal (and must be accepted by the > compiler) as long as you don't try to instantiate A. The > function Q<int>::fnc should only be instantiated (triggering the > error) if it is used. A virtual function is "used" if there is > an instance of the type, but as long as there is no instance, > a compiler is not allowed to instantiate it. That's very strange explanation. 'A' is not a template. Actually we have to apply the following rules with respect to Q<int>: 14.7.1/1: Unless a class template specialization has been explicitly instantiated (14.7.2) or explicitly specialized (14.7.3), the class template specialization is implicitly instantiated when the specialization is referenced in a context that requires a completely- defined object type or when the completeness of the class type affects the semantics of the program. 10/1: The class-name in a base-specifier shall not be an incompletely defined class (clause 9) Since the specialization Q<int> is not explicitly instantiated nor explicitly specialized, and it is used as a base-specifier, it shall be completely defined class and it is implicitly instantiated. Then the following rule applies: 14.7.1/9: 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. > (A really clever compiler might be able to warn that there is no > type T which could result in a valid fnc, but it can't trigger > an error unless it is actually called on to instantiate fnc.) If my understanding of the rules is correct, whether a valid specialization of Q<T>::fnc can exist depends on implementation's choice. Obviously, T and Q<T> are distinct types, so the conversion from T* to Q<T>* is possible only if T is derived from Q<T>: template<typename T> struct Q { virtual Q* fnc() { return new T; } }; // point of instantiation for Q<D> // possible point of instantiation for Q<D>::fnc struct D : Q<D> { // .... }; If an implementation implicitly instantiates Q<D>::fnc, the point of instantiation for Q<D>::fnc is located as marked above (according to 14.6.4.1/4). At this point the class D is still incomplete, so the new- expression would be invalid. Other points of instantiation for Q<D>::fnc can be located after the definition of D. Otherwise, all points of instantiation (if they exist) for Q<D>::fnc are located after the definition of D, and the function definition is correct. There is also one very unclear rule: 14.6/7: "If no valid specialization can be generated for a template definition, and that template is not instantiated, the template definition is ill-formed, no diagnostic required." According to literal interpretation, the following code is ill-formed template <class T> class X { void f(); }; // template definition template <class T> void X::f() { return 0; } but we can't apply this rule to the next code: template <class T> class X { // not a template definition void f() { return 0; } }; Probably that's a defect in the standard (and in C++0x draft), so an implementation could consider template<typename T> struct Q { virtual Q* fnc() { return new T; } }; as ill-formed code (according to its choice with respect to implicit instantiation of virtual functions). -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Daniel Krügler on 26 Jul 2010 13:46 On 27 Jul., 00:18, "Johannes Schaub (litb)" <schaub-johan...(a)web.de> wrote: > Daniel Kr�gler wrote: > > On 26 Jul., 01:56, DeMarcus <use_my_alias_h...(a)hotmail.com> wrote: > >> Consider this template. > > >> template<typename T> > >> struct Q > >> { > >> virtual Q* fnc() { return new T; } > >> }; > > >> If I now declare a variable like this > > >> Q<int> qi; > > >> I get the following from gcc 4.5.0. > >> "error: cannot convert 'int*' to Q<int>*' in return". > > >> That seems perfectly correct. But now try this > > >> struct A : Q<int> > >> { > >> }; > > >> and it complies perfectly fine with gcc 4.5.0!!! That must be a bug, > > right? > > > This is not a bug, but an explicit freedom, the Standard > > provides to implementors of templates: In contrast to > > non-virtual functions, virtual functions may lead to > > an immediate member instantiation, even, if not > > used, see 14.7.1/9 (Both C++03 and FCD): > > > "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." > > This was precisely the paragraph i was arguing athttp://groups.google.com.mt/group/comp.std.c++/browse_thread/thread/7... > using the interpretation you use in this post :) Your answer back then was > different: You seemed to say that it would not imply instantiating a > definition. > > Did i misunderstand your statement back then? I still don't understand it, > fwiw. The "It is unspecified ..." part seems totally redundant to me, > because the ODR rule you quoted already requires instantiation for non-pure > virtual functions, and does not require it for pure functions. What would be > different if we would remove the "It is unspecified ...." sentence? The example in our former discussion involved a *pure* virtual function, but this is not the case in the OP's example. 14.7.1 does not require the existence of any definitions at all. The rules which finally require the existence of a function are given by 3.2/3+4 which do clearly say that a pure-virtual function is not considered as used and does not require any definition of those to exist, and additional in regard this discussion by 10.3/9: "A virtual function declared in a class shall be defined, or declared pure (10.4) in that class, or both; but no diagnostic is required (3.2)." Returning to 14.7.1, the effect of the requirements is that an implementation may instantiate all virtual function *declarations* and it also may instantiate all function *definition* it finds - this does not mean that this process is *requiring* the definitions to exist - this is all left to the ODR and 10.3/9! Thus, there is no reason to assume that suddenly 14.7.1 would imply the requirement for a definition of a pure virtual function, that is otherwise explicitly omitted. Returning to the OP's example: The fact, that an implementation *may* instantiate virtual function declarations and definitions (if they exist) has the effect that it can diagnose the ill-formed code - Nikolay gave a nice sequence of references of the normative wording which explains this more precisly as I did. HTH & Greetings from Bremen, Daniel Kr�gler -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Johannes Schaub (litb) on 27 Jul 2010 06:48
Daniel Kr�gler wrote: > On 27 Jul., 00:18, "Johannes Schaub (litb)" <schaub-johan...(a)web.de> > wrote: >> Daniel Kr�gler wrote: >>> On 26 Jul., 01:56, DeMarcus <use_my_alias_h...(a)hotmail.com> wrote: >>>> Consider this template. >> >>>> template<typename T> >>>> struct Q >>>> { >>>> virtual Q* fnc() { return new T; } >>>> }; >> >>>> If I now declare a variable like this >> >>>> Q<int> qi; >> >>>> I get the following from gcc 4.5.0. >>>> "error: cannot convert 'int*' to Q<int>*' in return". >> >>>> That seems perfectly correct. But now try this >> >>>> struct A : Q<int> >>>> { >>>> }; >> >>>> and it complies perfectly fine with gcc 4.5.0!!! That must be a bug, >>> right? >> >>> This is not a bug, but an explicit freedom, the Standard >>> provides to implementors of templates: In contrast to >>> non-virtual functions, virtual functions may lead to >>> an immediate member instantiation, even, if not >>> used, see 14.7.1/9 (Both C++03 and FCD): >> >>> "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." >> >> This was precisely the paragraph i was arguing >> athttp://groups.google.com.mt/group/comp.std.c++/browse_thread/thread/7... >> using the interpretation you use in this post :) Your answer back then >> was different: You seemed to say that it would not imply instantiating a >> definition. >> >> Did i misunderstand your statement back then? I still don't understand >> it, fwiw. The "It is unspecified ..." part seems totally redundant to me, >> because the ODR rule you quoted already requires instantiation for >> non-pure virtual functions, and does not require it for pure functions. >> What would be different if we would remove the "It is unspecified ...." >> sentence? > > The example in our former discussion involved a *pure* > virtual function, but this is not the case in the OP's > example. > > 14.7.1 does not require the existence of any definitions > at all. The rules which finally require the existence of > a function are given by 3.2/3+4 which do clearly say that > a pure-virtual function is not considered as used and does > not require any definition of those to exist, and additional > in regard this discussion by 10.3/9: > > "A virtual function declared in a class shall be defined, > or declared pure (10.4) in that class, or both; but no > diagnostic is required (3.2)." > > Returning to 14.7.1, the effect of the requirements is > that an implementation may instantiate all virtual > function *declarations* and it also may instantiate all > function *definition* it finds - this does not mean > that this process is *requiring* the definitions to exist > - this is all left to the ODR and 10.3/9! > > Thus, there is no reason to assume that suddenly 14.7.1 > would imply the requirement for a definition of a pure > virtual function, that is otherwise explicitly omitted. > > Returning to the OP's example: The fact, that an > implementation *may* instantiate virtual function > declarations and definitions (if they exist) has > the effect that it can diagnose the ill-formed code - > Nikolay gave a nice sequence of references of the > normative wording which explains this more precisly > as I did. > Ah thanks, i think i understand it now. The difference that it makes is to pure virtual functions. If there is a definition of the pure virtual function, the definition may be instantiatede even if it's not used. If there is no definition, the text imposes no other requirements. Is there normative text that says that implicit instantiation of a function is valid even if its definition is absent, though? Refering to Nikolay's most recent reply to you: If the text talks about implicitly instantiating a definition (which i think it does - because a declaration of it is instantiated anyway), what normative text grants for that implicit instantiation to be valid even if that definition cannot be located because it doesn't exist? I rather find the opposite. 14/8 says: "A non-exported template must be defined in every translation unit in which it is implicitly instantiated (14.7.1), unless the corresponding specialization is explicitly instantiated (14.7.2) in some translation unit; no diagnostic is required." This is gonna removed by C++0x, but i haven't found other wording that would say something different about implicit instantiation of function definitions. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |