Template deduction for nested classes P0293R0

Similar documents
Revision 8. John H. Spicer. November 3, 1994

Modules: ADL & Internal Linkage

Forward declaration of enumerations

Template Issue Resolutions from the Stockholm Meeting

John H. Spicer. September 26, This document attempts to clarify a number of namespace issues that are currently either

Modules: Contexts of Template Instantiations and Name Lookup Gabriel Dos Reis Microsoft

Wording for lambdas in unevaluated contexts

An Incomplete Language Feature

Short Notes of CS201

CS201 - Introduction to Programming Glossary By

Part X. Advanced C ++

Lambdas in unevaluated contexts

Lambdas in unevaluated contexts

An Alternative to Name Injection from Templates

C++ Module TS Issues List Gabriel Dos Reis Microsoft

P1267R0: Custom Constraint Diagnostics

The Compositional C++ Language. Denition. Abstract. This document gives a concise denition of the syntax and semantics

Class Types in Non-Type Template Parameters

Proposed Wording for Variadic Templates

Implicit Evaluation of auto Variables and Arguments

Extended friend Declarations

Tutorial 7. Y. Bernat. Object Oriented Programming 2, Spring Y. Bernat Tutorial 7

American National Standards Institute Reply to: Josee Lajoie

Proposed Wording for Variadic Templates (Revision 1)

The Syntax of auto Declarations

Templates Templates are functions or classes that are parameterized. We have already seen a few in STL:

Appendix. Grammar. A.1 Introduction. A.2 Keywords. There is no worse danger for a teacher than to teach words instead of things.

Introduction to Programming Using Java (98-388)

Deducing the type of variable from its initializer expression Programming Language C++ Document no: N1721=

Let return Be Direct and explicit

Introduction to Core C++

P0591r4 Utility functions to implement uses-allocator construction

Modules:Dependent ADL

Class Types in Non-Type Template Parameters

COMP 181. Agenda. Midterm topics. Today: type checking. Purpose of types. Type errors. Type checking

Eliminating the Class Rvalue. Standard Conversion. January 28, 1996

Deducing the type of variable from its initializer expression (revision 4)

Protection Levels and Constructors The 'const' Keyword

Technical Specification: Concepts

Auxiliary class interfaces

Introduction to Standard C++

Working Draft, C++ Extensions for Concepts

Abstract This paper proposes the ability to declare multiple variables initialized from a tuple or struct, along the lines of:

CS93SI Handout 04 Spring 2006 Apr Review Answers

Structured bindings with polymorphic lambas

Decltype (revision 6): proposed wording

std::optional from Scratch

Basic Templates Intro

Working Draft, Extensions to C++ for Modules

Modules:Context-Sensitive Keyword

Note in particular that users of the standard are not special in this: abuse of these rules is generally bad usage for any library.

Implicit Evaluation of auto Variables and Arguments

Tokens, Expressions and Control Structures

template <typename T> // unless it s an unqualified pointer struct IsPtr<T *> { enum { r = true }; };

Overview. 1. Expression Value Categories 2. Rvalue References 3. Templates 4. Miscellaneous Hilarity 2/43

Botet C++ generic match function P0050

Using Enum Structs as Bitfields

Type Inference auto for Note: Note:

CPSC 427: Object-Oriented Programming

Working Draft, C++ extensions for Concepts

Outline. 1 About the course

C++ Important Questions with Answers

Static Semantics. Winter /3/ Hal Perkins & UW CSE I-1

Tutorial 6. Y. Bernat. Object Oriented Programming 2, Spring Y. Bernat Tutorial 6

Auto - a necessary evil?

Working Draft, C++ Extensions for Concepts

Expansion statements. Version history. Introduction. Basic usage

Allowing Class Template Specializations in Associated Namespaces (revision 1)

Part III. Advanced C ++

Proposal to Simplify pair (rev 4)

Deducing the type of variable from its initializer expression (revision 3)

Rvalue References as Funny Lvalues

Simplifying C++0x Concepts

Increases Program Structure which results in greater reliability. Polymorphism

SFU CMPT Topic: Class Templates

Cpt S 122 Data Structures. Templates

Assignment 1: grid. Due November 20, 11:59 PM Introduction

CSC1322 Object-Oriented Programming Concepts

3. Basic Concepts. 3.1 Application Startup

C++ Yanyan SHEN. slide 1

Layout-compatibility and Pointer-interconvertibility Traits

Interview Questions of C++

CSCI 171 Chapter Outlines

Bind Returned/Initialized Objects to the Lifetime of Parameters, Rev0

Proposal for Extending the switch statement

Introduction to C++ Introduction to C++ Dr Alex Martin 2013 Slide 1

simd<t> Finding the right set of traits for Document Number: P0964R1 Date: Matthias Kretz Target: Parallelism TS 2


How the Adapters and Binders Work

Abstract This paper proposes the ability to declare multiple variables initialized from a tuple or struct, along the lines of:

Fast Introduction to Object Oriented Programming and C++

Algorithmic "imperative" language

Modern and Lucid C++ Advanced for Professional Programmers. Part 7 Compile-Time Computation. Department I - C Plus Plus

Comp151. Function Templates & Class Templates

Debug C++ Without Running. Anastasia Kazakova

Supporting Class / C++ Lecture Notes

OBJECT ORIENTED PROGRAMMING USING C++

Chapter 1 INTRODUCTION SYS-ED/ COMPUTER EDUCATION TECHNIQUES, INC.

static CS106L Spring 2009 Handout #21 May 12, 2009 Introduction

Type checking of statements We change the start rule from P D ; E to P D ; S and add the following rules for statements: S id := E

Transcription:

Template deduction for nested classes P0293R0 S. Davis Herring October 14, 2016 Audience: EWG 1 Abstract Because type names nested inside a dependent type may be typedef-names, template deduction is not attempted on them. However, nested classes in a class template can be referenced only with names of that form and thus may never be deduced. This restriction is severe in contexts like partial specialization and conversion function templates where template arguments must be deduced. This paper proposes to shrink this non-deduced context to allow nested classes to be deduced, but to retain the part necessary to avoid ill-posed deduction problems. Code like the following is then possible: template<class T> struct C { struct iterator { /*... */ ; iterator begin(); //... ; template<class T> struct Q { using type=int; type count(); //... ; template<class T> void fc(typename C<T>::iterator); template<class T> void fq1(typename Q<T>::type); template<class T> void fq2(typename Q<T>::type,T); void f() { C<int> c; Q<int> q; fc(c.begin()); // invalid in C++14; calls fc<int> here Q<int>::type i=q.count(); // "Q<T>::type", but that's just int! fq1<int>(i); // no deduction: same meaning as in C++14 fq2(i,42); // deduce from 42: same meaning as in C++14 2 Problem It is currently impossible to deduce T in the call to fc because a nested-name-specier is always a non-deduced context 1. Obviously the example's intent is trivial to understand; the reason for forbidding deduction there herring@lanl.gov 1 14.8.2.5 [temp.deduct.type] paragraph 5.1 1

has to do with typedef-names instead, as in Q. The mapping from T to Q<T>::type is non-invertible: even though the argument to fq1 is int, there is no unique T to use. In general the inverse mapping is undecidable. 3 Context The restriction is particularly burdensome for constructor templates and partial specializations, where deduction is required for any use at all. Dening a function template or a partially specialized class template for a set of related nested classes is a natural application, and working around the restriction on doing so is a frequent topic of discussion (see, e.g., http://stackoverflow.com/questions/12640808/ nested-template-and-parameter-deducing). There are workarounds available for the case of function templates. The idea from the BartonNackman trick can be used to approximate a (non-member) function template: struct B {; friend void f(b) { ; f(b); // finds f(a<int>::b) via ADL The Curiously Recurring Template Pattern can be used to discover the nested class type (and, with a bit more work, the parameters of the containing instantiation): template<class T> struct C {; struct B : C<B> { typedef T outer; long x; ; ; template<class T> typename T::outer f(c<t> &c) { T &t=static_cast<t&>(c); return static_cast<typename T::outer>(t.x); int g() { return f(b); // calls f(c<a<int>::b>&) However, neither of these approaches works for partial template specialization, and each requires altering the classes in question (which is of course frequently impractical). Instead of a typedef-name A<T>::type, the programmer may and should instead use the real (dependent) type name if one exists. (The substitution cannot be automatic precisely because T is unknown.) However, the only form of class name that supports deduction is X<T,...> for some template X (that is not itself an alias template) 2 ; nested classes lack any name of that form! Unfortunately, even when a class template denes a normal nested class, the possibility remains that a specialization of it might introduce an indirect type denition. It therefore may seem that there is no safe way to allow deduction in this context. 4 Restricted solution However, when deduction is performed, an actual type is always available. In considering whether a parameter type like C<T>::iterator might match the actual type, it is known whether the actual type is a nested 2 14.8.2.5 [temp.deduct.type] paragraph 8 2

class. If it is not, or if its (unqualied) name is not iterator, then deduction is not attempted (and thus does not fail); otherwise, deduction may proceed using the type denoted by the nested-name-specier as the parameter type and the actual type's containing class as the (new) actual type. This procedure works even if the member class is an instantiation of a member template: C<T>::iterator<U> may be matched by checking that the actual type is an instantiation of a member class template named iterator, and if so doing deduction on C<T> against the containing class and on <U> against the template arguments of the actual type. Alias templates that expand to the name of a nested class (or instantiation of a member class template) can also be treated; they cannot be specialized, so they may be expanded in the declaration before attempting deduction. Finally, the simpler case of T::iterator can be handled trivially. 5 Practicalities This change may aect existing code by causing additional function template overloads to become applicable or by allowing deduction failures from the additional deduced contexts. An example of the latter, where an additional context provides a result that conicts with that of a context already supported: struct B {;; template<> struct A<char> {using B=A<int>::B;; template<class T> void f(t,typename A<T>::B); f('c',b); // error: T could be char or int In C++14, there is no way to deduce T as int, so the deduction as char succeeds. The call also succeeds because, as it happens, the type of b is that indicated by the typedef-name A<char>::B. To preserve the meaning of as many programs as possible, it is important that deduction not fail entirely in a case beyond even these relaxed rules. Rather, such usage simply remains a non-deduced context. (This failure avoidance is similar to that in 14.8.2.5 [temp.deduct.type] paragraph 5.5.1.) However, newly attempted deductions may nontheless fail according to existing rules, for example because of e.g., 14.8.2.5 [temp.deduct.type] paragraph 17: template<int i> struct A {struct B {;; template<short s> struct S {; template<short s> void f(typename A<s>::B,S<s>); A<1>::B b; S<1> s; f(b,s); // error: can't deduce short s=1 from A<int=1> In C++14, no attempt is made to deduce s from the rst argument. (It might be preferable in general to have such cases produce no template argument values rather than cause the entire deduction to fail.) Finally, referring to a nested class via a member typedef-name with the same unqualied name can cause a deduction failure: struct B {;; template<class T> struct Q {using B=typename A<T>::B;; template<class T> void f(typename Q<T>::B); f(b); // error: no deduction for Q<T>/A<int> 3

This failure could be avoided by further complicating the non-deduced context, more or less stating that the context is deduced if and only if deduction succeeds in it. It can be stated much more simply in terms of the idea that deduction should be able to produce no result without failing per se. Because the syntax for a nested class is identical to that for a member typedef-name, allowing deduction for one may mislead programmers into thinking it allowed for the other (which remains inadvisable!). Therefore it would be benecial for implementations to produce warnings when the dependent name in question is a typedef-name (or not dened at all). However, since in some cases the template arguments can be supplied explicitly, and forthcoming specializations may introduce nested classes, the program is not ill-formed because of the use of such a dependent name, even when (as for partial specialization) there appears at the point of declaration to be no way for it to be used. 6 Wording Based on N4604. To be resolved: 14.8.2.1 paragraph 4.3 may need to be updated to generalize P has the form simpletemplate-id. Change 14.8.2.5 paragraph 5.1 to read The nested-name-specier of a type that was specied using a qualied-id, unless the actual type is a nested class (or, if the unqualied-id is a template-id, an instantiation of a member class template) whose name is the same as that used in the trailing unqualied-id. Change the rst and last examples in paragraph 6 to read If a type is specied as AX<T>::BY<T2>, both T and T2 are non-deduced, unless A is a specialization of a member class template named Y. If a type is specied as void f(typename A<T>::B, A<T>), the T in A<T>::B is non-deduced but the T in A<T> is deduced even if that in A<T>::B is non-deduced. Add to paragraph 8 the forms nested-name-specifier ::name nested-name-specifier ::name <T> nested-name-specifier ::name <i> and note after the list that nested-name-specier here must contain T, TT, and/or i. Add a new paragraph before paragraph 9 If P has a form that contains ::name, then A is a nested class or instantiation of a member class template named name. The types denoted by the nested-name-specier s, and in the latter case the unqualied-ids, in P and A are compared. Or else it would be a non-deduced context, per paragraph 5.1. Add to subsection C.4.6: 14.8.2.5 Change: Allowance to deduce a nested class type. Rationale: Allows use of nested classes with partial template specialization and conversion function templates. Eect on original feature: Valid C++ 2014 code may fail to compile or produce dierent results in this International Standard: struct Base {; struct B : Base {; ; 4

void f(base&); template<class T> void f(typename A<T>::B&); // previously could not be deduced f(b); // calls f(a<int>::b&); previously called f(base&) 5