19

The C++ Language Standard states the following concerning template components in the Standard Library:

The effects are undefined...if an incomplete type is used as a template argument when instantiating a template component, unless specifically allowed for that component (C++11 §17.6.4.8/2).

Does the following cause instantiation of the std::vector class template?

class X;
std::vector<X> f(); // Declaration only; we will define it when X is complete

To ask it another way, in the function declaration std::vector<X> f();, is std::vector instantiated with the argument X? Or, is std::vector<X> not instantiated until f() is odr-used or defined?

Likewise, does the following cause instantiation of the std::vector class template?

class X;
typedef std::vector<X> XVector; // We will complete X before we use XVector

While I use std::vector in these examples, the question applies equally to all templates.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • A good answer will provide references to the C++ Language Standard. I searched through the Language Standard but was unable to find a definitive answer. – James McNellis Oct 11 '11 at 18:45
  • I've never seen "undefined" used with part of the compilation process before... – Mooing Duck Oct 11 '11 at 18:45
  • Why do you want to know? – i_am_jorf Oct 11 '11 at 18:47
  • Why are you convinced it is indeed Instantiating the template component, when you commented [here](http://stackoverflow.com/questions/7730211/c-class-method-returns-vectorsubclass/7730244#7730244), Any thoughts? – Alok Save Oct 11 '11 at 18:48
  • @jeffamaphone: I want to know because I am curious. Also, because it has wide-ranging practical implications, as demonstrated by the debate [in the answers and comments to this question](http://stackoverflow.com/questions/7730211/c-class-method-returns-vectorsubclass). – James McNellis Oct 11 '11 at 18:48
  • @MooingDuck: not ending a source file with a new-line was undefined behavior till C++11. – Yakov Galka Oct 11 '11 at 18:48
  • @Als: I am no longer convinced, so I have asked this question. – James McNellis Oct 11 '11 at 18:49
  • @Mooing Duck When it think about it, it makes sense to be undefined. It allows things like the pimpl idiom with shared_ptrs. The C++ committee is quite impressive in its ability to make the language tools as general as possible. – Paul Manta Oct 11 '11 at 19:01
  • I need to learn from your skill to take a point of uncertainty in an obscure little side question and elevate it to an award-winning question in its own right :-) +1 – Kerrek SB Oct 11 '11 at 19:15
  • @Paul: I don't think pimpl nor shared_ptrs use undefined behavior. pimpl doesn't require anything related to this question. – Mooing Duck Oct 11 '11 at 19:46
  • @Paul: `std::shared_ptr` (along with `std::unique_ptr` and several other templates) falls under the _unless specifically allowed for that component_ part of the rule I cited. The `std::shared_ptr` specification states "The template parameter `T` of `shared_ptr` may be an incomplete type." (§ 20.7.2.2/2). `std::unique_ptr`'s specification has similar wording. There are specific cases where each of the smart pointer types requires a complete `T`; [Howard Hinnant wrote a nice overview explaining the details](http://home.roadrunner.com/~hinnant/incomplete.html). – James McNellis Oct 11 '11 at 22:16

2 Answers2

5

§ 14.7.1\1 Implicit instantiation [temp.inst]

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. 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. Unless a member of a class template or a member template has been explicitly instantiated or explicitly specialized, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist; in particular, the initialization (and any associated side-effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.

§ 8.3.5\9 Functions [dcl.fct]

Types shall not be defined in return or parameter types. The type of a parameter or the return type for a function definition shall not be an incomplete class type (possibly cv-qualified) unless the function definition is nested within the member-specification for that class (including definitions in nested classes defined within the class).

§ 3.1\2 Declarations and definitions [basic.def]

A declaration is a definition unless it declares a function without specifying the function’s body (8.4), it contains the extern specifier (7.1.1) or a linkage-specification25 (7.5) and neither an initializer nor a function-body, it declares a static data member in a class definition (9.4), it is a class name declaration (9.1), it is an opaque-enum-declaration (7.2), or it is a typedef declaration (7.1.3), a using-declaration (7.3.3), a static_assert-declaration (Clause 7), an attribute-declaration (Clause 7), an empty-declaration (Clause 7), or a using-directive (7.3.4).

It's only instantiated if it's required. I couldn't find a clear definition anywhere, but the second quote says that those declaratations are not definitions, which seems to be the same to me.

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
  • Interesting. However, this answer seems inconclusive... the first sentence is especially problematic, I think. On the one hand, the type is used in a context where an incomplete type is allowed. On the other hand, it seems that "the completeness of the class type affects the semantics of the program," no? – James McNellis Oct 11 '11 at 21:42
  • Though really, it is not _the completeness of the class type_ itself that affects the semantics of the program; it is _the completeness of the type with which the class template is instantiate_ that affects the semantics of the program. Hmmmmmmmmmmm.... – James McNellis Oct 11 '11 at 21:59
  • I think by semantics of the program, it basically means referring to a member of the object. [EDIT no wait, that's syntax] Since we don't do that, and the size of the object doesn't matter, an incomplete type is allowed. – Mooing Duck Oct 12 '11 at 16:06
2

No, it does not instantiate the template. Mooing Duck's answer provides all the necessary quotes, but here is some analysis.

Instantiation, by default, cannot occur if nothing exists to require a completely-defined type (§14.7.1/1). Function definitions specifically require complete types (§8.3.5/9), but the question is whether some other part of the standard also requires this for other declarations.

But there's a special exception for definitions, which reveals that non-definition declarations really are different:

The type of a parameter or the return type for a function definition shall not be an incomplete class type (possibly cv-qualified) unless the function definition is nested within the member-specification for that class (including definitions in nested classes defined within the class).

What's special about function definitions inside member-specifications? Because a member-specification cannot declare the same function twice (§9.2/1), and member function bodies are processed after all member declarations (§3.3.7/1.1). Essentially, a nested member function definition is treated as a declaration during the first pass, and then a definition once the entire member-specification has been processed, and the class is complete (§9.2/2). And §8.3.5/9 specifies that an incomplete class is permissible for that first pass, but not the second.

It's pretty onerous to perform an exhaustive, definitive search of the Standard's rules for function declarations and instantiations. But this example, although limited to member functions and the completeness of the enclosing type, can reasonably be extended to other functions and types. In any case, it's pretty good evidence of a distinction.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421