27. Exceptions
28.5 Attributes for interoperation
30.2.2 Type arguments
This subclause lists the types that can and cannot be generic arguments. Fundamental types are not included in either set, neither are function types. The subclause does not say whether or not cv-qualified types are allowed.[[#162]]
A generic type or function is instantiated from a generic declaration by specifying type arguments that correspond to that generic declaration’s type parameters. Type arguments are specified via a generic- 25 argument-list: generic-argument-list: generic-argument generic-argument-list , generic-argument generic-argument: 30 type-id
The arguments for an instantiation of a generic class shall always be explicitly specified. The arguments for an instantiation of a generic function (§30.3) can either be specified explicitly, or they can be determined by type deduction.
A generic-argument shall be a constructed type that is a value class, a handle to a ref class, a handle to a 35
delegate, a handle to an interface, a handle to an Array, or it shall be a type parameter from an enclosing generic. [Note: It is not possible to use a native class, a pointer, a reference, a handle to a value class, or a ref class by value as a generic argument. end note]
Each generic-argument shall satisfy any constraints (§30.4) on the corresponding type parameter.
30.2.3 Base classes and interfaces 40
A constructed class type has a direct base class. If the generic class declaration does not specify a base class, the base class is System::Object. If a base class is specified in the generic class declaration, the base class
of the constructed type is obtained by substituting, for each generic-parameter in the base class declaration, the corresponding generic-argument of the constructed type. [Example: Given the generic class declarations
generic<typename T, typename U>
45
Generics
the base class of the constructed type D<int> would be B<String^, array<int> >. end example] Similarly, constructed ref class, value class, and interface types have a set of explicit base interfaces. The explicit base interfaces are formed by taking the explicit base interface declarations on the generic type declaration, and substituting, for each generic-parameter in the base interface declaration, the corresponding generic-argument of the constructed type.
5
The set of all base classes and base interfaces for a type is formed, as usual, by recursively getting the base classes and interfaces of the immediate base classes and interfaces. [Example: For example, given the generic class declarations:
ref class A { … }; generic<typename T>
10
ref class B : A { … }; generic<typename T>
ref class C : B<IComparable<T>^> { … }; generic<typename T>
ref class D : C<array<T> > { … };
15
the base classes of D<int> are C<array<int> >, B<IComparable<array<int>^> >, A, and
System::Object. end example]
30.2.4 Class members
The non-inherited members of a constructed type are obtained by substituting, for each generic-parameter in the member declaration, the corresponding generic-argument of the constructed type. The substitution 20
process is based on the semantic meaning of type declarations, and is not simply textual substitution. It would be helpful to explain this in more detail and/or give an example where this makes a difference. [Example: Given the generic class declaration
generic<typename T, typename U> ref class X {
25
array<T>^ a;
void G(int i, T t, X<U,T> gt);
property U P { U get(); void set(U value); }
int H(double d);
};
30
the constructed type X<int, bool> has the following members: array<int>^ a;
void G(int i, int t, X<int,bool>^ gt);
property bool P { bool get(); void set(bool value); } int H(double d);
35
end example]
The inherited members of a constructed type are obtained in a similar way. First, all the members of the immediate base class are determined. If the base class is itself a constructed type, this might involve a recursive application of the current rule. Then, each of the inherited members is transformed by substituting, for each generic-parameter in the member declaration, the corresponding generic-argument of the
40
constructed type. [Example:
generic<typename U> ref class B { public: U F(long index); 45 }; generic<typename T>
ref class D : B<array<T>^> { public:
T G(String^ s);
50
In the above example, the constructed type D<int> has a non-inherited member intG(String^ s)
obtained by substituting the type argument int for the type parameter T. D<int> also has an inherited member from the class declaration B. This inherited member is determined by first determining the members of the constructed type B<array<T>^> by substituting array<T>^ for U, yielding array<T>^F(long index). Then, the type argument int is substituted for the type parameter T, yielding the inherited member
5
array<int>^F(longindex). end example]