Ru-Brd |
13.8 The typeof OperatorWhen writing templates, it is often useful to be able to express the type of a template-dependent expression. Perhaps the poster child of this situation is the declaration of an arithmetic operator for a numeric array template in which the element types of the operands are mixed. The following example should make this clear: template <typename T1, typename T2> Array< ??? > operator+ (Array<T1> const& x, Array<T2> const& y); Presumably, this operator is to produce an array of elements that are the result of adding corresponding elements in the arrays x and y . The type of a resulting element is thus the type of x[0]+y[0] . Unfortunately, C++ does not offer a reliable way to express this type in terms of T1 and T2 . Some compilers provide the typeof operator as an extension that addresses this issue. It is reminiscent of the sizeof operator in that it can take an expression and produce a compile-time entity from it, but in this case the compile-time entity can act as the name of a type. In our previous example this allows us to write: template <typename T1, typename T2> Array<typeof(T1()+T2())> operator+ (Array<T1> const& x, Array<T2> const& y); This is nice, but not ideal. Indeed, it assumes that the given types can be default- initialized . We can work around this assumption by introducing a helper template as follows : template <typename T> T makeT(); // no definition needed template <typename T1, typename T2> Array<typeof(makeT<T1>()+makeT<T2>())> operator+ (Array<T1> const& x, Array<T2> const& y); We really would prefer to use x and y in the typeof argument, but we cannot do so because they have not been declared at the point of the typeof construct. A radical solution to this problem is to introduce an alternative function declaration syntax that places the return type after the parameter types: // operator function template: template <typename T1, typename T2> operator+ (Array<T1> const& x, Array<T2> const& y) -> Array<typeof(x+y)>; // regular function template: template <typename T1, typename T2> function exp(Array<T1> const& x, Array<T2> const& y) -> Array<typeof(exp(x, y))> As the example illustrates, a new keyword (here, function ) is necessary to enable the new syntax for nonoperator functions (for operator functions, the operator keyword is sufficient to guide the parsing process). Note that typeof must be a compile-time operator. In particular, typeof will not take into account covariant return types, as the following example shows: class Base { public: virtual Base clone(); }; class Derived : public Base { public: virtual Derived clone(); // covariant return type }; void demo (Base* p, Base* q) { typeof(p->clone()) tmp = p->clone(); // tmp will always have type Base } Section 15.2.4 on page 271 shows how promotion traits are sometimes used to partially address the absence of a typeof operator. |
Ru-Brd |