Difference between revisions of "DIP40"

From D Wiki
Jump to: navigation, search
(Example)
(Example)
 
Line 69: Line 69:
 
template foo(T3){
 
template foo(T3){
 
struct A(T1){ //not in scope
 
struct A(T1){ //not in scope
 +
    this()(T1 a) {}
 +
}
 +
}
 +
 +
template A(T1){
 +
struct A{ //not in scope unless T1 is explicitly instantiated
 
     this()(T1 a) {}
 
     this()(T1 a) {}
 
}
 
}

Latest revision as of 07:25, 14 May 2013

DIP 40: Template parameter deduction for constructors

Title: Template parameter deduction for constructors.
DIP: 40
Version: 1
Status: Draft
Created: 2013-05-12
Last Modified: 2013-05-12
Author: Timothee Cour
Links:

Abstract

A proposed feature of C++14 is to introduce template parameter deduction for constructors, see paper, mentioned here. The idea is to deduce template parameters when calling a constructor given the arguments given to the constructor, whenever possible. A compile error occurs when the deduction is ambiguous. The benefits would be:

  • make the code more DRY
  • make boilerplate of class instantiators unnecessary in most cases (they're all over phobos, eg: std.typecons.tuple, std.typecons.rebindable etc)
  • make D more consistent: it deduces template parameters for functions, so why not for constructors, when this is unambiguous?
  • it won't break any code.

Note, just as for deduction of normal functions, it should work with 0 or more template parameters specified (ie the first k>=0 templates may be provided).

Example

import std.typecons;
auto a=Tuple!(int, double)(1,1.0); //not DRY
auto a=tuple(1,1.0); //boilerplate in std.typecons: requires auxiliary class instantiator function 'tuple' just to allow this
auto a=Tuple(1,1.0); //proposed syntax that deduces type parameters

Another example:

struct A(T1)
if(isNumeric!T1 && !is(T1==float))
{
	this(T2) if(!isNumeric!T2) (T2 a, T1 b){}
	this()(T1 b){}
	this()(){}
}
struct A(T1)
if(isNumeric!T1 && is(T1==float))
{
	this()(){}
}
struct A(T1)
if (!isNumeric!T1)
{
    this()(T1 a) {}
}

template foo(T3){
struct A(T1){ //not in scope
    this()(T1 a) {}
}
}

template A(T1){
struct A{ //not in scope unless T1 is explicitly instantiated
    this()(T1 a) {}
}
}

static if(false){ 
struct A(T1){//not in scope
    this()(T1 a) {}
}
}


auto a=A(1,1.0); //deduced to A!(double)(1,1.0)
auto a=A(1.0); //deduced to A!(double)(1.0)
auto a=A(); //error: T1 cannot be deduced.
auto a=A(Object.init,1.0); //error: no matching type

Deduction

Step 1) Find all matching class/struct types in scope, temporarily ignoring the template constraints (the 3 struct A definitions in our example)

Step 2) For each type in step 1, find all constructors, temporarily ignoring the template constraints (3 + 1 + 1 in our example)

Step 3) This constitutes our overload set. For each element in the overload set,

  • form list of template parameters that is the concatenation of the ones in the type and the ones in the constructor (in our example, the 1st one has 2 template parameters (T1,T2) and all the others have 1).
  • form list of template constraints as a logical AND of the ones in the type and the ones in the constructor

With this transformation, the problem is now the same as for template deduction of normal functions: we apply the usual template deduction rules are used, taking into account the number of parameters and compatibility of template constraints.

Step 4) If there is an ambiguity or no match, give an error, otherwise instantiate.

Extension

A possible extension is to also allow template parameter deduction for static functions, using the same mechanism as for templates.

Copyright

This document has been placed in the Public Domain.