Difference between revisions of "DIP40"
Timotheecour (talk | contribs) (→DIP 40: Template parameter deduction for constructors (do not read yet, still editing)) |
Timotheecour (talk | contribs) (→Example) |
||
(4 intermediate revisions by the same user not shown) | |||
Line 50: | Line 50: | ||
<syntaxhighlight lang="d"> | <syntaxhighlight lang="d"> | ||
struct A(T1) | struct A(T1) | ||
− | if(!is(T1==float)) | + | if(isNumeric!T1 && !is(T1==float)) |
{ | { | ||
− | this(T2)(T2 a, T1 b){} | + | this(T2) if(!isNumeric!T2) (T2 a, T1 b){} |
this()(T1 b){} | this()(T1 b){} | ||
this()(){} | this()(){} | ||
} | } | ||
struct A(T1) | struct A(T1) | ||
− | if(is(T1==float)) | + | if(isNumeric!T1 && is(T1==float)) |
{ | { | ||
this()(){} | 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,1.0); //deduced to A!(double)(1,1.0) | ||
auto a=A(1.0); //deduced to A!(double)(1.0) | auto a=A(1.0); //deduced to A!(double)(1.0) | ||
auto a=A(); //error: T1 cannot be deduced. | auto a=A(); //error: T1 cannot be deduced. | ||
+ | auto a=A(Object.init,1.0); //error: no matching type | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | == 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 == | == Extension == |
Latest revision as of 07:25, 14 May 2013
Contents
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.